Final & Working guide for living with multiple Git accounts

permlink: https://gist.github.com/benjaminv/092f3d87afcbe589ca2a03fa9358050f
first publish: Jun 13, 2022
updated: Sep 20, 2024

1. Generate a new SSH key-pair for each of Git account.

$ ssh-keygen -t rsa -b 4096 -C "[email protected]" -f ~/.ssh/id_rsa_benjaminv_github
$ ssh-keygen -t rsa -b 4096 -C "[email protected]" -f ~/.ssh/id_rsa_bendhu_github
$ ssh-keygen -t rsa -b 4096 -C "[email protected]" -f ~/.ssh/id_rsa_benhu1_gitlab

# The -C option is a comment to help identify the key.
# The -f option specifies the file name for the key pair.

2. Add the SSH keys to your SSH-agent

$ ssh-add ~/.ssh/id_rsa_benjaminv_github
$ ssh-add ~/.ssh/id_rsa_bendhu_github
$ ssh-add ~/.ssh/id_rsa_benhu1_gitlab

Verified by $ ssh-add -l, the result should look like follows,

# work github
4096 SHA256:UY1sId6R**********************6faASkLkUI9BY [email protected] (RSA)
# work gitlab
4096 SHA256:+k2fsrBl**********************olO/obXFSNOA [email protected] (RSA)
# personal github
4096 SHA256:FcTyaa8T**********************CfKUt5J1lMIIY [email protected] (RSA)

And make these persistent for new terminal sessions by enable AddKeysToAgent yes in Section 4.

3. Add the public keys to your GitHub accounts respectively.

Visit https://github.com/settings/keys and use “New SSH Key”

# copy public key to clipboard without opening it
% pbcopy < ~/.ssh/id_rsa_benjaminv_github.pub
% pbcopy < ~/.ssh/id_rsa_bendhu_github.pub
% pbcopy < ~/.ssh/id_rsa_benhu1_gitlab.pub

paste the public key to your GitHub account and add a name to identify it.

4. Managing Overall SSH-Keys

By default the file needed is located at ~/.ssh/config

add following lines to the end of the file

# Work github account
Host github.com
HostName github.com
User git
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519_work_github

# Work gitlab account
Host gitlab.com
HostName gitlab.com
User bgit
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa_gitlab

# Personal github account
Host github.com.personal
HostName github.com
User git
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa_benjaminv_github

5. Which Account to Use by Default?

The global Git configuration file is stored at $HOME/.gitconfig on all platforms. This defines the default values for all Git commands.

[user]
email = [email protected]
name = ben
[init]
defaultBranch = main # stop using master as default branch

to edit it,

$ git config --global user.name "ben"
$ git config --global user.email "[email protected]"

6. Config User Account for Project

this whole Section 6 is no longer needed after you complete Section 9

6.1 Cloning GitHub repositories using no-default accounts

instead of using github.com:benjaminv/benjaminv, use github.com.personal:benjaminv/benjaminv to match the configuration in ~/.ssh/config

% git clone [email protected]:benjaminv/react-crash-2021.git
# mind the HostName github.com.personal

6.2 Update the local user

use cat .git/config to check the current git config Then

% git config --local user.name "ben"
% git config --local user.email "[email protected]"

6.3 Update the remote git url

for repo already cloned before this configuration

% git remote set-url origin "[email protected]:benjaminv/starting-react.git"
# mind the .personal added to github.com

6.4 Add remote git url

for newly created repo and local project

% git remote add origin "[email protected]:benjaminv/starting-react.git"
# mind the .personal added to github.com

6.5 verify the local repo config

% cat .git/config

# It looks like following

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
[remote "origin"]       # @github.com.personal:
        url = [email protected]:benjaminv/starting-react.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
        remote = origin
        merge = refs/heads/main
[user]                  # current user
        name = ben
        email = [email protected]

7. Confirming the Other Account is Working

% ssh -T [email protected]
# Hi benjaminv! You've successfully authenticated, but GitHub does not provide shell access.
# Mind the username here, it is benjaminv NOT my default Git account name

8. Push to remote repository

# change local branch name if necessary
% git branch -M <new-branch>
# push to remote repository
% git push origin <new-branch>

9. Want to auto-match of git profile? Pro only

Say, all my codes are in ~/Documents/__Code__ and my work projects sit in ~/Documents/__Code__/Work/ while my hobby projects sit in ~/Documents/__Code__/Ben/. How may I make my current Terminal shell knowing that which git user should it use when I conduct git operations, such as git fetch git pull git push?

The ultimate setup will be like this,

Step 1: Edit your global (default) git config

# path: ~/.gitconfig
[user]
        email = [email protected]
        name = ben
[init]
        defaultBranch = main
[http]
        postBuffer = 500M
        maxRequestBuffer = 100M
[core]
        compression = 0
[credential]
        helper = store

[includeIf "gitdir:~/Documents/__Codes__/Work/"]
    path = ~/Documents/__Codes__/Work/.gitconfig

[includeIf "gitdir:~/Documents/__Codes__/Ben/"]
    path = ~/Documents/__Codes__/Ben/.gitconfig

!important

  • if your OS is case-sensitive you will have to match the file path by gitdir:~/My_Project_Path no space in the string
  • if your OS is NOT case-sensitive you might consider using /i param to allow free cases in the path string, e.g., gitdir/i:~/My_Project_Path no space in
  • according to docs you need the tailing / at end of path, i.e. ~/Documents/__Codes__/Work/

    Step 2: Make your local (path specific) git configs

Working git user:

# path: ~/Documents/__Codes__/Work/.gitconfig

[user]
        email = [email protected]
        name = ben
[init]
        defaultBranch = main
[http]
        postBuffer = 500M
        maxRequestBuffer = 100M
[core]
        compression = 0
[credential]
        helper = store

Personal git user:

# path: ~/Documents/__Codes__/Ben/.gitconfig
[user]
        email = [email protected]
        name = benjaminv
[init]
        defaultBranch = main
[http]
        postBuffer = 500M
        maxRequestBuffer = 100M
[core]
        compression = 0
[credential]
        helper = store
[url "[email protected]"]
        insteadOf = [email protected]

Then you are good to go. Thankfully, this works for both CLI and VSCode GUI (yes!!! regardless which github user you logged in on VSCode)

Although…

There is one more glitch here, VSCode GUI uses https protocols instead of ssh ONLY when you push local repo directly to GitHub by automatically create a public / private repository for you. Instead of adding [email protected]:benjaminv/shopify-dawn-theme.git as your repo remote, it adds https://github.com/benjaminv/shopify-dawn-theme.git you can verify this by git remote -v

The real fix

Update in VSCode settings git protocol from default https to ssh

The fix
git remote set-url origin [email protected]:benjaminv/shopify-dawn-theme.git
TL;DR
// desired, so that url matching in ~/Documents/__Codes__/Ben/.gitconfig can work like a magic

git remote -v
...
[remote "origin"]
        url = [email protected]:benjaminv/shopify-dawn-theme.git
        fetch = +refs/heads/*:refs/remotes/origin/*
...
// wrong, this will be different from all (global, then company and personal) .gitconfig profiles

git remote -v
...
[remote "origin"]
        url = https://github.com/benjaminv/shopify-dawn-theme.git
        fetch = +refs/heads/*:refs/remotes/origin/*
...

// it will result this,
> git push -u origin main
remote: Repository not found.
fatal: repository 'https://github.com/benjaminv/shopify-shopify-theme.git/' not found

p.s.

Don’t confuse yourself with git repo authentication and your local git user switch.

git repo authentication

The first part of this guide is dealing with git authentication, regardless your current path, check with pwd, you still need add .personal to git hostname, as we defined in ssh auth profiles, e.g, git clone [email protected]:benjaminv/my-hobby-project.git to connect to your repo

local git user switch by path

The section 9. Want to auto-match of git profile? Pro only is dealing with local git user switch.

References

  • https://gist.github.com/jexchan/2351996?permalink_comment_id=4456452#gistcomment-4456452