This post is for people who need to work on repositories owned by different GitHub accounts, for example their personal one and their “work account” part of their company’s team. Juggling authentication credentials can be annoying, but a few configuration options will make it much easier.

A typical setup: one account

One of the first steps when starting with Git is to configure your name and email. Git will in fact use them to sign all your commits and, if not set, it will try to guess them from your system environment and present you a warning.

If you host your code on GitHub setting your email address will be even more important, as GitHub uses emails to associate commits to user accounts.

This means that once you have this in your git config:

1
2
3
git config --global -l
user.email=myname@email.com
user.name=My Name

you’ll be able to commit, push, and then find your commit history on GitHub embellished with your avatar and with links to your profile page.

Another thing that a GitHub user has to decide is what kind of URL to use to reference a repository remote: either SSH or HTTPS.

It is arguably more secure and flexible to use a SSH URL rather than HTTPS, because a HTTPS URL:

  • will require you to type your username and password everytime you push or fetch (yes, the same goes for private key passphrases, but they are less sensitive than your account password);
  • the above can be avoided by using a credential helper to remember your password, which is a bad idea, especially if you’re using a laptop (what’s the point of having a password if anyone with access to your computer can bypass it?);
  • it will not work if you have enabled two factor authentication anyway, or rather it will require you to setup an access token and use that to authenticate.

In addition to be (again, arguably) more secure, SSH references and authentication are easier to configure.
In my SSH tutorial I wrote on how to use a SSH config file to declare which private keys to use for which hosts. Since git will communicate with GitHub via SSH, we can use the ~/.ssh/config file to configure this connections:

1
2
3
Host github.com
    IdentityFile ~/.ssh/your_personal_github_private_key.id_rsa
    User git

With that set, git is ready to automatically authenticate requests to GitHub. If your key has a passphrase (good!) it will prompt you to type it each time. There are ways to cache it, although the same considerations I made for the git credential helpers apply here.

What if we have multiple accounts

So far, we have described a fairly standard setup.

Things become a bit messier when you have work-related repositories on your personal computer and are accessing them with a different GitHub account that you use for work stuff.
This poses two challenges:

  1. Git should not sign your work commits with your personal email, otherwise GitHub will associate them to the wrong user account.
  2. When interacting with the remote (git clone/push/fetch) git should authenticate the requests with the work account, not the personal one.

How to handle multiple identities

The first problem is quite easy to solve.
All we need to do is to configure different name and email values only for the repositories associated to your alternative account, which can be done using the --local flag instead of --global.
In order to use git config --local we need to be inside a repository directory: the keys will be written to the ./.git/config file rather than ~/.gitconfig (used when configuring with --global). These config values will only apply to that specific repo, but they will also override any property already set at the higher --global or --system levels.

So, while the --local configuration usually only contains repo-specific stuff like the remotes’ URLs or the branch names, we can execute this to add extra keys:

1
2
3
cd repo_dir
git config --local user.name "Name Surname"
git config --local user.email "name.surname@company.com"

The result will be the following snippet, which will ensure that a different email and name will be used to sign the commits in this repository:

1
2
3
4
5
6
7
git config --global -l
user.name=My Name
user.email=myname@email.com

git config --local -l
user.name=Name Surname
user.email=name.surname@company.com

Problem #1 is solved.

How to handle multiple authentication credentials

This requires a few more changes, but nothing too difficult.

We’ve already seen how a repository’s remotes have URLs pointing to a server, for example:

1
2
3
git remote -v
origin  git@github.com:account_name/repo_name.git (fetch)
origin  git@github.com:account_name/repo_name.git (push)

We’ve also seen how, with that style of URLs, git will check the ~/.ssh/config file to decide which private key to use.
With that in mind, the solutuon to problem #2 is to setup git to use a different SSH configuration for certain repositories.

Let’s start with the SSH config file, where we will add a new host alias:

1
2
3
4
5
6
7
8
Host github.com
    IdentityFile ~/.ssh/your_personal_github_private_key.id_rsa
    User git

Host work-github.com
    HostName github.com
    IdentityFile ~/.ssh/work/your_work_github_private_key.id_rsa
    User git

The first group is what we already had.
The second one is interesting. work-github.com is not a real domain name, we’re making it up, and for this reason we add the HostName line to provide the actual domain name to use when the SSH agent will try to open a connection to the fake host alias. The effect is that SSH connections to github.com will use the first configuration group, while connections to work-github.com will use the second group but will still use the real GitHub URL. Also notice how the second group references a different private key file, associated to another GitHub account: this will cause the SSH agent to authenticate to GitHub as a different user.

The next step is to update the remote’s URL in the repository:

1
2
3
4
5
git remote set-url origin git@work-github.com:account_name/repo_name.git

git remote -v
origin  git@work-github.com:account_name/repo_name.git (fetch)
origin  git@work-github.com:account_name/repo_name.git (push)

That’s it. Now every time you will git push/fetch or git remote prune origin, git will open a SSH connection to the host alias, will use the special configuration in the SSH config file, and will actually connect to github.com using the private key of your work account.

Working with your personal repositories will still work as it always has: the remotes’ URLs will still reference the real GitHub domain, and git will use the normal SSH configuration with your personal private key.

And what about cloning?

If you need to clone a new repository from the work GitHub organization, you can use the new host alias from the beginning to set up the remote’s URL automatically:

1
git clone git@work-github.com:account_name/new_repo.git

And if you’ve already set things up correctly, you will not need anything else.