Let the System Remember: Multiple Git Accounts

Shannon Cartier Lucy: Woman with Shoestrings, 2019

Spent an hour reverse-engineering my own Git multi-account setup. 🙃 It turns out that the "hacky" approach—using SSH host aliases with fake hostnames—works better than the "correct" one. Why? Loud failure beats silent failure, and state beats process. Every "just remember to..." is a bug waiting to happen.

I spent an hour this morning trying to figure out how my Git setup works. I configured it three years ago and hadn't thought about it since. That's a sign it works.

The problem: I have two GitHub accounts. When I push code, Git needs the right SSH key and the right identity. Wrong key = push fails. Wrong identity = my personal email ends up in my employer's commit history.

The standard solution comes from a gist circulating since 2017: SSH host aliases. Clone personal repos with git@github-personal instead of git@github.com. The SSH config maps each alias to a different key. Looks hacky. Works.

A commenter complained: why fake hostnames when you could set an environment variable? GIT_SSH_COMMAND="ssh -i ~/.ssh/personal-key" git push keeps the "correct" URL.

Sounds reasonable until you forget. With host aliases, using the wrong one gets you a permission denied error—the push fails, you fix it, you move on. With environment variables, forgetting to set one means the push succeeds with the wrong identity. You've leaked your personal email into a work repo and you won't know until someone notices.

Loud failure beats silent failure.

The deeper principle: host aliases encode your choice in the repo's configuration. Clone with github-personal, every subsequent operation uses the right key. Environment variables require the right choice on every operation.

State versus process. When a decision should persist, encode it in state. Database constraints over application validation. Type systems over runtime checks. SSH aliases over env vars you have to remember.

For attribution—user.name and user.emailgit-autoconfig prompts you to pick an identity when you open an unconfigured repo. A fallback.

Better: Git's conditional includes. Directory structure encodes the decision:

[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig-work

Clone into the right folder. Everything else follows.

Clone into the wrong folder and you'll notice on first commit—wrong author. Fix it by moving the repo to the right directory, or run git config user.email "right@email.com" to override locally. The conditional include is a default, not a cage.

You can go further with Git's url.insteadOf directive, which rewrites URLs automatically. Clone with git@github.com and Git silently converts it to the right host alias based on directory. Too much magic. I'd rather be explicit at clone time than let the system guess based on directory. If you trust your directory discipline, one less thing to remember.

The best configuration is invisible. If you're constantly remembering to do something, that's a bug.

Every "just remember to..." is a bug.