If you need to use more than one git account and SSH key, you’ll quickly run into the problem of per-repository configuration.

I was recently stuck having to migrate all my work repositories to a new, work-only account (thanks to a combination of auth changes and the lack of email configuration in Bitbucket).

Previously I’d used one Bitbucket account for everything, so had never had to do per-repository authentication in git. I found most tutorials skipped some detail or other, so this is the process that worked for me including the gotchas.

Create new SSH key

I didn’t want to share an SSH key across auth boundaries so I made a new one:

$ ssh-keygen

Remember to set a different filename, as you probably already have id_rsa (here we’ll make it id_rsa_user2 and pretend the first one was id_rsa_user1 for ease of reference). Obviously set a good password too.

As it’s a new set of keys, ensure their permissions are correct:

$ chmod 600 ~/.ssh/id_rsa_user2
$ chmod 600 ~/.ssh/id_rsa_user2.pub

Finally, add the new key to your SSH agent:

$ ssh-add ~/.ssh/id_rsa_user2

Add the new public key to Bitbucket

In this case the config URL in Bitbucket's web UI would be https://bitbucket.org/account/user/user2/ssh-keys/. The only real trick here is being careful you put the right key into the right account.

Create SSH host aliases

You’ll need to create an alias for each key, ~/.ssh/config:

Host bitbucket.org-user1
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_rsa_user1

Host bitbucket.org-user2
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_rsa_user2

Note that user1 and user2 are the Bitbucket usernames.

If you mostly use one SSH key, you probably want to just make that the default and only alias the one you use less:

Host bitbucket.org
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_rsa

Host bitbucket.org-user2
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_rsa_user2

This means for your primary account, everything works as normal and you don't have to set aliased git remote URLs for all repos; just the ones with the specific alias.

If config is a new file, you’ll need to set permissions:

$ chmod 600 ~/.ssh/config

Update 2017.01.28 - if you are using OSX Sierra+ and want Keychain to manage your SSH passwords, add some extra lines:

Host bitbucket.org-user1
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_rsa_user1
  UseKeychain yes
  AddKeysToAgent yes

Host bitbucket.org-user2
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_rsa_user2
  UseKeychain yes
  AddKeysToAgent yes

Set URLs to use the aliases

For a new checkout, just clone via the alias and your remotes will be configured for you:

$ git clone origin git@bitbucket.org-user1:foo/foo.git

For an existing checkout, update your remote URLs. You can check these with a verbose check:

$ git remote -v
origin  git@bitbucket.org-user1:foo/foo.git (fetch)
origin  git@bitbucket.org-user1:foo/foo.git (push)

To update the URL:

$ git remote set-url origin git@bitbucket.org-user1:foo/foo.git

Configure user details per repo

Updating the name is optional, but you will need to set the appropriate email in each repo:

git config user.name "User One"
git config user.email user1@example.com

I found non-matching emails were rejected. That is, you can't claim to be using an email address attached to a different account.

What about other git hosts?

The process is the same regardless of git host, just sub in the URL as required.

Done

All done - each repo should now work as normal, the most obvious side effect is having to add two keys when you start your SSH agent (on OSX you won't need to worry as keychain handles that for you). This process worked for me in OSX Terminal and Windows Subsystem for Linux (WSL).

Update 2017.01.28

A couple of gotchas have surfaced since this was originally published:

  • If you use any private packages in NPM, Bower, etc you will need to add your host alias in the relevant json files. That does mean you can't check that into source unless you have your entire team use the same alias, eg. bitbucket.org-teamname. If your whole team needs multi-key setup this is fine, but if it's just you then it's a lot of stuffing around for everyone else. So if you're just setting out to do this you may want to set your team alias as the real hostname and your personal as the aliased hostname.
  • OSX Sierra changed the way it handled SSH keys, so my note about keychain handling it is no longer accurate. You'll need to update your SSH configuration to use the proprietary UseKeychain yes and AddKeysToAgent yes options in each alias; and you may need to explicitly add all of your SSH keys (ssh-add -K ~/.ssh/id_rsa && ssh-add -K ~/.ssh/id_rsa_user2 etc) before it will all work. I recommend a quick google for osx sierra ssh agent to get started.