I wanted one machine to handle both personal and work GitHub without constant account confusion. This setup solved it by isolating three things:
- Git commit identity (name/email)
- SSH authentication key
- GitHub CLI session (
gh)
I use fictional accounts in this guide:
- Personal: alex-dev
- Work: acme-engineer
The mental model
I stopped thinking in terms of "switching accounts" and started thinking in terms of "context decides account."
- Folder decides Git identity
- Remote host alias decides SSH key
- Command alias (
ghpvsghw) decides GitHub CLI account
No global toggling needed.
1) Route Git identity by folder
Choose folder roots:
~/Desktop/Dev/personal/~/Desktop/Dev/work/
In ~/.gitconfig:
[user]
useConfigOnly = true
[includeIf "gitdir:~/Desktop/Dev/personal/"]
path = ~/.gitconfig-personal
[includeIf "gitdir:~/Desktop/Dev/work/"]
path = ~/.gitconfig-work
Create ~/.gitconfig-personal:
[user]
name = alex-dev
email = alex-dev@users.noreply.github.com
Create ~/.gitconfig-work:
[user]
name = acme-engineer
email = alex.chen@acme.com
Verify
Inside a personal repo:
git config user.name
git config user.email
Inside a work repo:
git config user.name
git config user.email
Expected: personal repo returns personal identity; work repo returns work identity.
2) Route SSH auth by host alias
Goal: give each account its own SSH identity path, then map it with host aliases.
Setup pattern (works for both work and personal)
For each account, choose one: - Reuse existing key if that key is already in the correct GitHub account - Create a new key if no key exists yet
Where to check existing keys: - GitHub -> Settings -> SSH and GPG keys
How to confirm a local key matches GitHub:
ssh-keygen -lf ~/.ssh/id_rsa.pub
ssh-keygen -lf ~/.ssh/id_ed25519_github_personal.pub
Compare SHA256 fingerprints from terminal with what GitHub shows.
Example: work account
If reusing existing key:
- Keep using ~/.ssh/id_rsa (or your current work key path)
If creating a new key:
ssh-keygen -t ed25519 -C "alex.chen@acme.com" -f ~/.ssh/id_ed25519_github_work
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github_work
Add the matching .pub key to the work GitHub account in
Settings -> SSH and GPG keys -> New SSH key (key type: Authentication Key).
Example: personal account
If creating a new key:
ssh-keygen -t ed25519 -C "alex-dev@users.noreply.github.com" -f ~/.ssh/id_ed25519_github_personal
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github_personal
Then add ~/.ssh/id_ed25519_github_personal.pub to the personal GitHub account.
In ~/.ssh/config:
Host *
AddKeysToAgent yes
UseKeychain yes
Host github-work
HostName github.com
User git
# Use one of the following:
# IdentityFile ~/.ssh/id_rsa
# IdentityFile ~/.ssh/id_ed25519_github_work
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github_personal
IdentitiesOnly yes
Repeat the same pattern for the other account: reuse if already present, otherwise create and add.
Verify
ssh -T github-work
ssh -T github-personal
Expected: - Work alias authenticates as work account - Personal alias authenticates as personal account
3) Isolate GitHub CLI with zsh wrappers
By default, gh keeps one active account per host.
So I created two wrappers that use separate config directories.
Add to ~/.zshrc:
ghp() { GH_CONFIG_DIR="$HOME/.config/gh-personal" gh "$@"; }
ghw() { GH_CONFIG_DIR="$HOME/.config/gh-work" gh "$@"; }
Reload shell:
source ~/.zshrc
Login once per profile:
ghp auth login --hostname github.com --git-protocol ssh
ghw auth login --hostname github.com --git-protocol ssh
Verify
ghp auth status -h github.com
ghw auth status -h github.com
Expected:
- ghp shows personal user
- ghw shows work user
4) Use alias-based remotes in every repo
This is the final lock that keeps things deterministic.
- Personal repo remote format:
git@github-personal:alex-dev/repo-name.git- Work repo remote format:
git@github-work:acme-org/repo-name.git
Set or fix origin:
git remote set-url origin git@github-personal:alex-dev/repo-name.git
# or
git remote set-url origin git@github-work:acme-org/repo-name.git
Verify
git remote -v
Expected: remote uses github-personal or github-work, not plain github.com.
5) Daily workflow (no account switching)
- Keep personal repos in
~/Desktop/Dev/personal/.... - Keep work repos in
~/Desktop/Dev/work/.... - Use
git pushnormally. - Use
ghp ...for personal GitHub CLI actions. - Use
ghw ...for work GitHub CLI actions.
Quick pre-push sanity check:
git config user.name
git config user.email
git remote -v
Troubleshooting cheatsheet
Permission denied (publickey)- Wrong key on account, or wrong host alias in remote.
-
Check
~/.ssh/config, then runssh -T github-work/ssh -T github-personal. -
Wrong commit identity
- Repo not under your include path, or include file has wrong values.
- Check
git config --show-origin --get user.name. -
Confirm you are inside a Git repo with
git rev-parse --is-inside-work-tree. -
ghshows wrong account - You used plain
ghinstead of wrapper. - Use
ghporghw, then... auth status -h github.com.
Why this works long-term
This setup removes memory-based switching and replaces it with structure-based routing: - path -> identity - remote alias -> SSH key - wrapper command -> GitHub CLI profile
That is what makes it reliable months later, including for "future me."