<<

Managing Multiple Github Accounts On One Machine

For a whole bunch of reasons, it’s possible to end up with multiple Github accounts - it’s a good idea to keep personal and professional Github accounts separate, for example.

That implies there are situations where it’s necessary to work with multiple Github accounts on the same machine - and that can be painful.

I was usually caught out by this when in a hurry to commit a bug fix, and there were times when I ended up tweaking code in the Github UI rather than fight with local configs.

Finally, I’ve got around to fixing this once and for all. Here is a process which while not making it pain-free, at least makes it possible with as little hassle as possible.

Assumptions

  • You’ve already created the Github accounts and the online side of Github is working.
  • You’re doing this on a Mac or similarly *nixy flavoured system.
  • I’m using the terms “personal” and “work” accounts in this example, but it would work equally well if you’ve got different Github accounts for different clients or similar.

How it works

The entire process depends on two factors:

  • separate SSH keys for each Github identity (this is enforced by Github themselves)
  • leveraging git’s ability to conditionally-configure settings depending on where the git-managed project is located in the file system.

Sort out your directory structure

You’ll need to start by separating your personal and professional code bases into separate directories - this is how I’ve structured mine:

~
└── data/
   └── code/
       ├── personal/
       │   ├── project_1/
       │   ├── project_2/
       │   ├── project_#/
       └── work/
           ├── project_1/
           ├── project_2/
           ├── project_#/

Exactly how you set this up is a matter of taste, but it makes the git configuration a lot easier if all directories containing git-managed code sit underneath one main directory, and you separate the projects from each Github account into a separate subdirectory structure.

Any new projects that you create within the personal or work directories will automatically pick up the relevant Github credentials once you’ve completed the setup.

Assuming that works for you, this is the process to get things working properly.

Create SSH keys locally

In this step, you’ll create separate SSH keys, one for each Github account.

  1. In a terminal, switch to the ~/.ssh directory
  2. Create a new SSH key for each Github account that you want to work with
    • ssh-keygen -t rsa -C "your-email-address" -f "github-username"
    • ssh-add --apple-use-keychain <ssh key name>

This step is semi-optional if you’ve already got SSH keys set up - just create any that are missing.

Add the new SSH keys to Github

You’ll need to do this 5-step process for each Github account in turn:

  1. While still in the ~/.ssh directory, copy the public key to the clipboard with pbcopy < ~/.ssh/<keyname>.pub
  2. Log into Github with the credentials for the relevant account (it’s worth double-checking this, because you don’t want to get the SSH keys mixed up between accounts.)
  3. Click on your avatar at top right, select the Settings menu option and then the SSH and GPG keys item
  4. Add a new SSH key by clicking on the New SSH keybutton
  5. Paste in the public key that you copied in step 1, give it a name, and add it.

Repeat this process for the other Github account(s), remembering to login to that account before adding the SSH key.

Update your SSH config

Still in the ~/.ssh directory, create (or edit the existing) config file.

Here, you’re going to create an entry for each Github account:

~/.ssh/config

# personal account
Host github.personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/personal


# work account
Host github.work
  HostName github.com
  User git
  IdentityFile ~/.ssh/work

You can call the accounts whatever you like, but make sure that the Host value in each section is different. The hostname should be github.com in both sections. You’ll see why this is important in a moment.

Sort out the git configuration

Create local .gitconfig files

You’re going to create THREE .gitconfig files:

  • one “master” config, which applies to all projects
  • one “personal” config, which applies only to personal projects
  • one “work” config, which applies only to work projects

The master config just tells git where to look for the other configs; while the other configs control which Github identity gets used.

Master config

We’ll start with the master config. In your “root” code directory - that’s ~/data/code in my structure - create an empty .gitconfig file:

~
└── data/
   └── code/
       ├── .gitconfig <-- global config file
       ├── personal/
       └── work/

Update the contents:

# ~/data/code/.gitconfig

[includeIf "gitdir/i:~/data/code/personal/"]
    path = ~/data/code/personal/.gitconfig.personal

[includeIf "gitdir/i:~/data/code/work/"]
    path = ~/data/code/work/.gitconfig.work

This conditionally-loads one of the two config files, depending on which directory the local repo finds itself. This is where the magic happens, basically - it switches the non-SSH values as needed to allow the full push/pull process to work.

You’ll need to adjust the paths after the gitdir/:i to fit your directory structure.

Local .gitconfigs

Now let’s create the “local” git configs. You need to do this twice, once for each of the Github accounts:

~
└── data/
   └── code/
       ├── .gitconfig <-- global
       ├── personal/
       │   └── .gitconfig.personal <-- personal
       └── work/
           └── .gitconfig.work <-- work

The contents of both files have the same structure:

[user]
  email = <email address associated with the Github account>
  name = <your name>

[github]
  user = <your github username>

[credential]
  username = <your github username>

Insert the appropriate values for email, user, and username for the relevant account.

Using the process

Now that we’ve got this set up, it’s time to use it for real.

The SSH side of the process relies on replacing the github.com hostname in the repo’s URL with the hostname that you defined in the SSH config:

  • for a “personal” repo, you would use git@github.personal
  • for a “work” repo, you would use git@github.personal

For example, the Github repo URL for this site is git@github.com:timd/trashpanda.cc.git

When I’m working with the repo locally, however, that gets replaced with git@github.personal:timd/trashpanda.cc.git

Then in conjunction with the local git configuration in the relevant subdirectory, the correct Github credentials will automatically be applied when pushing and pulling.

Using this process when cloning a repo for the first time

To do this when cloning an existing repo, copy the repo URL from the Github site, and edit it to replace your “local” details, e.g instead of

  • git clone git@github.com:timd/trashpanda.cc.git

you would need to edit this to

  • git clone git@github.personal:timd/trashpanda.cc.git

Once you’ve done this, all git commands work exactly the same as they did before, and you can basically forget about this entire process.

Using this process with an existing cloned repo

If you already have a repo locally, that’s not a problem - you can update the repo’s URL with the “new” value, for example:

git remote set-url origin git@github.personal:timd/trashpanda.cc.git

Pushes and pulls to this repo will now use the “new” settings and pick up the correct Github credentials.

Summary

This is about as fool-proof as it’s possible to get in everyday use - at the cost of a bit of configuration and remembering to get the URLs right when cloning for the first time, you get a process which is transparent during the bulk of Git/Github workflows.

You could also argue that you get a more neatly-organised directory structure as a bonus, but moving projects around a filesystem is trivial by comparison with tweaking SSH configurations etc.