Let the System Remember: Multiple Git Accounts
Shannon Cartier Lucy: Woman with Shoestrings
Summary
Spent an hour last week reverse-engineering my own Git multi-account setup. Two ways to keep work and personal apart. The SSH host-alias version uses made-up hostnames. Push from the wrong account and it dies right away on a name that doesn't resolve. The env-var version is neater and never says a word, which is how my personal email ends up on a work commit. I went with the one that trips me at the door, because I'm the part of this that forgets.
I spent an hour this morning trying to figure out how my own Git setup works. I set it up two years ago and hadn't touched it since. That's about the nicest thing you can say about any piece of infrastructure.
It's there because I have two GitHub accounts. Every time I push, Git has to grab the right SSH key and the right identity. Grab the wrong key and the push just dies. Grab the wrong identity and my personal email slips into my employer's commit history where I'd really rather it didn't live.
Most people reach for SSH host aliases here. The trick comes from a gist circulating since 2017: you clone personal repos with git@github-personal instead of git@github.com, and your SSH config points each alias at a different key. Looks like a hack. Runs fine.
Somebody in the comments pushed back. Why fake a hostname when an environment variable does the same job? GIT_SSH_COMMAND="ssh -i ~/.ssh/personal-key" git push and you keep the real URL.
Fair enough, right up until the morning you forget. And you will forget. With host aliases, a wrong guess earns you a permission-denied error, so you swear a little, fix the alias, and carry on. The environment-variable version has no such courtesy. Skip the variable and the push goes through anyway, wearing the wrong name. Your personal email is now sitting in a work repo and you find out weeks later when a coworker squints at the blame and asks who this is.
So I stay with host aliases, and the reason is that quiet failure. Clone once with github-personal and every push after that quietly finds the right key, no thinking required. The environment-variable approach hands that decision back to me on every single push, which is exactly the thing I am bad at remembering.
Same instinct that makes me reach for a database constraint instead of a check buried in application code. If a rule has to keep holding for years, I want it wired into the setup, not stashed in my memory of what I'm supposed to type at 9am.
Attribution is the other half, the user.name and user.email. git-autoconfig will nudge you to pick an identity the first time you open a repo it doesn't recognize, which is a decent safety net.
I like Git's conditional includes even more, because the folder you cloned into does the deciding for you:
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
Drop the repo in the matching folder and the right identity rides along. Drop it in the wrong one and your first commit shows up under the wrong author, which is annoying but loud. You move the repo, or you run git config user.email "right@email.com" to patch it locally. The conditional include is only a default. You can always talk it out of it.
There's a heavier version, url.insteadOf, which quietly rewrites git@github.com into the right alias based on where the repo lives. That's more magic than I want. I'd sooner be explicit at clone time than trust the system to read my folder layout and guess. If your directory habits are tidier than mine, it buys you one less thing to hold in your head.
Two years this thing has stayed out of my way, and on the day it finally slips it'll bark at me with a permission error instead of leaking something on the sly. Lately, any time I catch myself doing the same tiny manual step for the tenth or twentieth time, I stop and go rework the setup so I don't have to keep doing it. This morning that was worth an hour.