Multiple GitHub Accounts on One Machineο
If you have both a personal and a work GitHub account, you need a way to use each from the same machine without logging in and out. The solution is to give each account its own SSH key and tell Git which key to use based on where your repos live on disk.
Two separate concerns need to be managed:
Commit identity (name/email) β controlled by Git config
Authentication (which account) β controlled by SSH keys
The two are independent. Commits carry your name/email as a label. Pushes authenticate via SSH keys, which GitHub uses to identify your account.
Step 1: Create Two SSH Keysο
$ ssh-keygen -t ed25519 -C "personal@email.com" -f ~/.ssh/id_ed25519_personal
$ ssh-keygen -t ed25519 -C "work@email.com" -f ~/.ssh/id_ed25519_work
ed25519is the recommended algorithm for GitHub β modern, secure, and fast.The
-Cflag is just a comment/label on the key. It has no functional effect.The
-fflag sets the output filename.
Step 2: Configure SSH (~/.ssh/config)ο
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
User gitis required β GitHubβs SSH server only accepts the usergit. Your GitHub account is identified by the key, not the username.The
Hostaliases (github-personal,github-work) tell SSH exactly which key to use, rather than guessing.
Step 3: Upload Public Keys to GitHubο
Copy each public key and add it under GitHub β Settings β SSH and GPG keys β New SSH key.
$ cat ~/.ssh/id_ed25519_personal.pub # add to personal GitHub account
$ cat ~/.ssh/id_ed25519_work.pub # add to work GitHub account
Step 4: Configure Gitο
Keep shared config (aliases, etc.) in ~/.gitconfig. Create separate
files for each account that include it, then override identity and SSH URL.
[alias]
co = checkout
br = branch
ci = commit
st = status
[include]
path = ~/.gitconfig
[user]
name = Work Name
email = work@email.com
[url "git@github-work:"]
insteadOf = git@github.com:
[include]
path = ~/.gitconfig
[user]
name = Personal Name
email = personal@email.com
[url "git@github-personal:"]
insteadOf = git@github.com:
$ touch ~/.gitconfig-work ~/.gitconfig-personal
$ chmod 644 ~/.gitconfig-work ~/.gitconfig-personal
Note
Do not put identity ([user]) or [url] rewrites in ~/.gitconfig
itself β those belong only in the account-specific files. The base file
is included by both, so anything there applies everywhere.
Step 5: Create Personal Folderο
$ mkdir ~/personal
Note
Only the personal folder needs to be created. Any path outside of ~/personal
will automatically use the work config.
Step 6: Set Up Shell Hook (~/.bashrc)ο
GIT_CONFIG_GLOBAL overrides the path Git uses as its global config.
Override cd to update this variable whenever you change directories.
_update_git_config() {
if [[ "$PWD" == ~/personal* ]]; then
export GIT_CONFIG_GLOBAL=~/.gitconfig-personal
else
export GIT_CONFIG_GLOBAL=~/.gitconfig-work
fi
}
cd() {
builtin cd "$@"
_update_git_config
}
_update_git_config # run once on shell startup
After editing ~/.bashrc, reload it:
$ source ~/.bashrc
Note
The hook runs on cd, not on repo operations directly. This means
identity and URL rewriting are applied based on which directory you are
in when you run the Git command β including when cloning into a new
folder that is not yet a git repo.
How It Worksο
GIT_CONFIG_GLOBAL tells Git which file to use as its global config.
The shell hook keeps it pointed at the right account-specific file based
on your current directory. Both account files include ~/.gitconfig for
shared settings, then add their own identity and URL rewrite on top.
Why not use includeIf "gitdir:..."? That directive only activates inside
an existing git repo. When you run git clone from ~/personal/ β which
is not itself a repo β Git reads the global config before the repo exists,
so includeIf never fires and the work identity is used instead. The
GIT_CONFIG_GLOBAL approach works at the directory level regardless.
insteadOf rewrites remote URLs transparently. When you clone using
git@github.com:, Git silently rewrites the URL to use the correct SSH
host alias. This means you never have to type the alias manually.
$ cd ~/personal && git clone git@github.com:someuser/repo.git
# becomes: git@github-personal:someuser/repo.git
Folder |
SSH Host Used |
Git Identity |
|---|---|---|
|
|
|
Everything else |
|