Using Multiple GitHub Accounts on a Single Machine with Nix and Home Manager

Posted by Sean — 14 Dec 2022

There’s reasonable documentation available for how to manage multiple GitHub accounts on a single machine. This can be helpful if you have one account for personal use and another for your work. I came across another guide that made some improvements over GitHub’s basic instructions but, since I’m a special snowflake, I still couldn’t get quite the setup I wanted.

Here are my goals

  1. Ensure commits to personal repositories use my personal account and commits to work repositories use my work account.
  2. Use SSH, not HTTPS to interact with GitHub.
  3. Use separate SSH keys for personal and work accounts.
  4. Let me use standard git commands for everything. I don’t want to have to get used to a wrapper script or manually set environment variables.
  5. Manage all of this configuration using the Nix package manager and Home Manager on macOS.

Setting up Nix and Home Manager are beyond the scope of this article. I’ll assume you have them already up and running. I also don’t use Nix Flakes, so if that’s your thing, best of luck!

Now, on to making it work.

Configure SSH

We’ll need to configure SSH a bit, so add this to your home.nix:

programs.ssh = {
  enable = true;

  "*" = {
    extraOptions = {
      AddKeysToAgent = "yes";
      UseKeychain = "yes";
      IdentitiesOnly = "yes";
  };
};

Create separate personal and work SSH keys

Next, create the keys

ssh-keygen -t ed25519 -C "personal@example.com" -f ~/.ssh/id_ed25519_personal
ssh-keygen -t ed25519 -C "work@example.com" -f ~/.ssh/id_ed25519_work

Be sure to use a nice strong (different!) password for each one when prompted. Don’t worry, we’re going to store it in the keychain so you won’t have to type this very often.

Ensure ssh-agent is running

eval "$(ssh-agent -s)"

Now, add the keys. This is one of the rare times you’ll be prompted for those passwords you used for your keys.

ssh-add --apple-use-keychain ~/.ssh/id_ed25519_personal
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_work

OK, now we need to tell GitHub about these keys. First, grab the public key for your personal SSH key

pbcopy < ~/.ssh/ed25519_personal.pub

Then, log into your personal GitHub account and add this new SSH key to your account.

Repeat for your work account

pbcopy < ~/.ssh/ed_25519_work.pub

Configure git

With our SSH keys in place, we now need to configure git to use the right key at the right time. We also need to use the right email address when authoring commits. In my case, all of my work repositories live under a particular GitHub Organization, so I’m going to set up a rule to use my work SSH key and work email address for all repositories in that organization. For all repositories outside that organization, I’ll use my personal SSH key and email address. To do this, we’ll need to

  1. Modify the SSH command git invokes to use the right SSH key
  2. Modify git’s user.email config to use the right email address

We’ll accomplish this by configuring our personal SSH key and email address as the defaults, then overriding them when we’re in a work repository. Here’s our git configuration in Home Manager

programs.git = {
  enable = true;
  userName = "Your Name";
  userEmail = "personal@example.com";

  extraConfig = {
    core = {
      sshCommand = "ssh -i ~/.ssh/id_ed25519_personal";
    };
  };

  includes = [
    {
      contents = {
        user = {
	  email = "work@example.com";
	};

	core = {
	  sshCommand = "ssh -i ~/.ssh/id_ed25519_work";
        };
      };

      condition = "hasconfig:remote.*.url:git@github.com:WORK_ORGANIZATION/*";
    }
  ];
};

The trick here is in the includes section. Here, we specify an SSH command and email address to use instead of the default personal values. However, these work values are only used if the current repository has a git remote in WORK_ORGANIZATION. There are other conditions we could use. For example, if you keep your work repositories in a specific directory on your machine, like ~/work/ then you could use condition = "gitdir:~/work/";. In fact, that’s probably a better approach, since it won’t require you to jump through any hoops when initially cloning a repository from your work organization.

Fixing “MAC address could not be autodected” error from UUIDTools, Phusion Passenger and Ruby Enterprise Edition

Posted by Sean — 29 Aug 2008

I’m using the UUIDTools 1.0.3 gem in a Rails 2.1 application to generate globally unique IDs. After migrating the site to run under Phusion Passenger and Ruby Enterprise Edition I began encountering the following error:

StandardError (MAC address could not be autodetected.  Set the MAC address manually.):
    /vendor/gems/uuidtools-1.0.3/lib/uuidtools.rb:241:in `timestamp_create'
    /vendor/gems/uuidtools-1.0.3/lib/uuidtools.rb:229:in `synchronize'
    /vendor/gems/uuidtools-1.0.3/lib/uuidtools.rb:229:in `timestamp_create'
    ...

It seemed UUIDTools was trying to get the the network card’s MAC address (I’d guess to collect entropy), but couldn’t for some reason. I should also note that this is all running on an Ubuntu Hardy Heron 8.04, 512MB slice over at Slicehost (yes, that’s a referral link, use it! :-).

It turns out that UUIDTools was trying to use ifconfig to read the MAC address, but ifconfig wasn’t in the PATH. Since the application is now running under mod_rails, the relevant PATH is Apache’s PATH, which doesn’t include /sbin by default.

So, a quick edit of /etc/init.d/apache2 to change

ENV="env -i LANG=C PATH=/usr/local/bin:/usr/bin:/bin"

to

ENV="env -i LANG=C PATH=/usr/local/bin:/usr/bin:/bin:/sbin"

and a sudo /etc/init.d/apache2 restart was all it took to get the app back up and running.

GitHub Invite Giveaway

Posted by Sean — 07 Apr 2008

I’ve got a few GitHub invites available if anyone is interested. I’ve started putting a few of my open-source projects up there as well and so far it seems pretty cool.

Email link is in the footer, so come and get ‘em!

Update to EnkoderTags Radiant Extension

Posted by Sean — 16 Mar 2008

I’ve updated EnkoderTags to allow HTML attributes in the enkode_mailto tag. The attributes will get passed through untouched into the resulting markup, so you can add CSS classes or IDs to use as styling hooks. For example, this code

<r:enkode_mailto email="example@example.com" link_text="simple email example"
    class="enkodedlink"/>

will produce the HTML

<a href="mailto:example@example.com" class="enkodedlink">simple email example</a>

which will be obfuscated through the Enkoder as usual. Thanks to Nick Calladine for prompting me to add this feature!

Git Repositories for Rails Plugins

Posted by Sean — 09 Feb 2008

Having moved to git for managing my Rails projects and git submodules for Rails plugins and vendor/rails, I decided to create git mirrors for a couple of plugins whose maintainers use subversion.

If you have a Rails project in a git repository, you might do

git submodule add git://repo.or.cz/has\_many\_polymorphs.git vendor/plugins/has\_many\_polymorphs
git submodule add git://repo.or.cz/acts\_as\_ferret.git vendor/plugins/acts\_as\_ferret

and perhaps

git submodule add git://git.sanityinc.com/rails.git vendor/rails

followed by

git submodule init
git submodule update