Skip to content

Instantly share code, notes, and snippets.

@k4lizen
Last active November 28, 2024 15:44
Show Gist options
  • Save k4lizen/d1ef41d9aada4836a681b096a5d16a57 to your computer and use it in GitHub Desktop.
Save k4lizen/d1ef41d9aada4836a681b096a5d16a57 to your computer and use it in GitHub Desktop.
How to manage multiple git accounts with SSH

How to manage multiple git accounts (with SSH)

Guide for windows. Should apply similarly elsewhere. We will use SSH. If you only care about github, check these out: cli/cli#326 & https://github.com/cli/cli/releases/tag/v2.40.0.

The git side

When making a commit, the username and email tagged with the commit are the ones specified in git config user.name and git config user.email. For github at least (but probably for everything else as well), your email is used as your identifier, which connects you as the commit author to your profile on the hosting service.

I like to keep my email private, so the email I connect with my commits to github projects with is the noreply one provided by github. It can be found in github -> Settings -> Emails and looks like [email protected] the number at the beginning being the essentially only important part. If you change the name after the +, github will still recognize it as you, as long as the numbers are correct.

If you want to use some other repository hosting service, you will have to specify the email that you use for that one in your gitconfig. So, if you use the same public email throughout hosting services (i.e. dont use the provided private emails), you will only need one pair of SSH keys, and one .gitconfig for that email. If you want to keep your email private, you will have to make a new SSH key pair and .gitconfig for each account-service pair (i.e. for each unique service-provided private email). So if you have three different accounts you want to be able to swap between, and three different services you use (e.g. github, gitlab, codeberg), if you make your three emails public, and use them to author commits, you will only need 3 SSH key pairs and 3 .gitconfigs. If you wish to keep them private you will have to make 9 SSH key pairs and 9 .gitconfigs (for the nine private addresses the services provide you with). Note: Im not sure if all services provide a private email, if at least one which you use doesn't, you might as well use your public email(s) for all of them.

The user.name and user.email values can be set like so: git config user.name myname git config user.email [email protected]. Those settings are per-repository, and can also be changed by modifying the .git/config file. To set those values globally we can use the --global flag (git config --global user.name myname), or set them in the user-wide ~/.gitconfig file. It is annoying to have to change these values every time we want to swap to a different account. We will add this line to the global ~/.gitconfig:

[includeIf "gitdir:projects/work/"]
	path = ~/.gitconfig.work

And make a new file ~/.gitconfig.work which will have its own username and email:

[user]
	name = workname
	email = workemail

Seeing how gitdir works, projects/work/ will be turned to **/projects/work/**, and all repositories which have projects/work/ in their absolute path name will load the ~/.gitconfig.work, overriding our default global name/email to the one specified in it. Obviously adjust the paths to your filestructure as needed, but the point is: we will have separate folders which will have all the repositories for that account.

Okay, this would be enough if you just wanted to have the repositories locally. But if you ever want to push some changes, you will need a way to authenticate to your repo hosting service. There are some mechanisms in place for this to happen without SSH, like the git credential manager for windows, but I havent managed to get them to play along nicely, so SSH it is.

The SSH side

First setup SSH normally. You can do that by following Githubs docs. You don't need the Using SSH agent forwarding and Managing deploy keys sections. You're probably going to want to have ssh-agent start up automatically on system start. To do that follow this or go to Windows Services -> OpenSSH Authentication Agent -> Properties -> Startup Type and set it to Automatic. The Github docs also provide a snippet for starting it on shell start (i.e. profile load) but that doesn't seem to work for me.

Now to tell our ssh-agent when to use which keys, we are going to edit the .ssh/config file. You can see what the specific options do on the man page, but its gonna look something like this:

Host *
    IdentitiesOnly yes

# GITHUB

# work
Host github.com profigh workgh work profi 
    Hostname github.com
    User git
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/work_github

# private
Host privgh priv privategh private
	Hostname github.com
	User git
	PrefferdAuthentications publickey
	IdentityFile ~/.ssh/private_github


# GITLAB

# work
Host gitlab.com workgl workgitlab
    Hostname gitlab.com
    User git
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/work_gitlab

# private
Host privgl privategl privgitlab
	Hostname gitlab.com
	User git
	PrefferdAuthentications publickey
	IdentityFile ~/.ssh/private_gitlab

# CODEBERG
# CIRCLEHUT
# ....

Here, regardless if you use your public emails or private ones, you will need to write out all the account-service pairs. Though if your emails are public, youre not gonna have work_github and work_github SSH keys, but probably just work, which you will put for both github and gitlab. The point of the config is, if you want to use, for example, your work account on gitlab for a repository, you will take the SSH link which will look something like: [email protected]:myrepogroup123/reponame.git and change it to one of:

git@privgl:myrepogroup123/reponame.git
git@privategl:myrepogroup123/reponame.git
git@privgitlab:myrepogroup123/reponame.git

It doesn't matter which one. If you leave it as [email protected]:myrepogroup123/reponame.git, your work account SSH keys will be automatically selected. You will use that link then as the origin for the repository (so when doing git clone ... or git remote add origin ... ). Lets explain some options:

  • IdentitiesOnly yes will make it so that the agent only tries the given key-pair to connect, instead of trying everything it can find
  • Host x y z is a space delimited list of aliases for hostnames
  • Hostname the actual domain of the remote SSH server
  • IndentityFile ~/.ssh/private_github specifies the file in which you have your private key.

Wrong SSH agent

Git sometimes doesn't play well with the SSH agent, as it has its own. We want it to use ours. Older versions of git either don't, or barely, support SSH, so make sure to update your git version to the latest release. During Windows update/install there is an advanced setting on whether to use system SSH, or gits own SSH. Select system SSH, which should have come preinstalled at C:\Windows\System32\OpenSSH\ssh.exe. If you didn't do this, you can set it in your .gitconfig files with sshCommand:

[core]
	sshCommand = "C:/Windows/System32/OpenSSH/ssh.exe"

Important: Account leak, human error

If you set the origin url for the wrong account in some folder, it will work without any errors. E.g. if you do git clone git@privgl:myrepogroup123/reponame.git in the projects/work/ folder, make some changes and push them. Then, for anyone looking at the commit history, the will see your work user/email, even if that account doesn't have the permissions for that repository, since the push was performed using your private accounts SSH keys. The work accounts commits will even be verifiably signed (with the work account keys), if you set commit signing up. It will be obvious that you are the owner of both accounts, and that information leak may be something that you're trying to avoid. So take care to check if you are in the correct folder when setting origin url / cloning. If anyone knows a way to make this action fail rather than secretly mess you up, let me know.

Signing commits

You don't need to sign your commits, but its a nice way to verify you are who the commits authorship says you are (because anyone can put any name in git config user.name). There are some resources online on how to do it. Follow them. As a TLDR: You're going to want to upload your public signing key to your repo hosting service (can be the same as your auth key), and add the signingKey line to your .gitconfigs to point to their respectative keys.

[user]
    name = workname
    email = [email protected]
    signingKey = ~/.ssh/work.pub

Along with

[gpg]
    format = ssh

So git knows you're using SSH keys and not PGP keys. signingKey can also be the key itself, or the private key file etc. You can now sign your commits and tags with the -S flag like commit -S -m "my commit message!!", or if you're too lazy to add -S every time, you can add this to your .gitconfigs:

[commit]
    gpgsign = true
[tag]
    gpgsign = true

Which will make signing enabled by default. Verifying commit signatures is out of the scope of this gist. If you care about that, this guy seems to know what he is talking about (although he is using PGP).

If you have any tips to help with the workflow, let me know.

Some sources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment