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.
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.
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 findHost x y z
is a space delimited list of aliases for hostnamesHostname
the actual domain of the remote SSH serverIndentityFile ~/.ssh/private_github
specifies the file in which you have your private key.
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"
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.
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.