- How to use multiple github accounts from a single machine
- Generate ssh keys
- Add public keys to each github account
- Update
~/.ssh/configfile - Install keychain script
- Start ssh agent with keychain
- Test ssh connections
- Create directory structure
- Update ~/.gitconfig
- Commit helper
- Clone repositories
- How to contribute
- License is MIT
- See Also
I use multiple github accounts; for example, personal open source projects, work projects and some other projects. For a while, I ran into an annoying problem: after committing changes to a work repository, I would check the commit log only to find that commit was using my personal username and email.
This document is my solution to that problem. The goal is to set things up once and never have to think about it again. If I'm working on a work repository, I know the commits will automatically use my work identity, and the same goes for my personal and other repositories.
Even for a single github account, the ssh key management and git configuration techniques covered here are still worth adopting as good practice.
My work environment is macOS and Linux. If you'd like to add instructions for other platforms, please send a pull request. Please look at the How to contribute section for details.
If you already have some keys, use them instead of generating new keys. For new keys I use ed25519 now a days. They are short, very secure and perform faster.
Say I have 3 github accounts for various projects.
Please protect your private keys with strong passphrases. Do not create unprotected private keys.
- Personal account (github user: muquit)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_personal -C "git-personal" - Work account (github user: muquit2)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work -C "git-work" - Another account (github user: muquit3)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_projectx -C "git-x" Note: The comment specified with -C is purely metadata stored at the
end of the public keys for your own reference, to help you identify which
key is when you have several. github identifies account solely by the key's
fingerprint. The comment could be anything or nothing.
Try not to edit the public key manually to edit the comment, you may add a
new line unintentionally and break the key. Rather use -c flag with
ssh-keygen to change a comment. Example:
ssh-keygen -c -f ~/.ssh/id_ed25519_personalssh-kegen -c operates directly on the key file on disk, not through
ssh-agent. So it will ask for passphrase regardless of whether the key
is loaded in the agent. It will show the old comment and will prompt for
the new comment.
- Login to github with that account
- Go to Settings -> SSH and GPG keys -> New SSH key
- Paste the content of the corresponding
.pubkey file
Note: github does not allow the same public key on multiple accounts. Each account must have a unique key.
This step is important. We'll create Host alias for each account that
maps to github.com but uses a different key. Example:
# Personal github account
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
# Work github account
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
# Third account
Host github-projectx
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_projectx
IdentitiesOnly yes
Note:
-
Usermust begit- github always usesgitas the ssh user. It identifies the account by the ssh key, not the username. -
IdentitiesOnly yes- without this, ssh-agent (man ssh-agentfor more info) offers all loaded keys and github accepts the first valid one, which may be the wrong account. -
Host aliases -
github-personal,github-workandgithub-projectxare arbitrary names I chose. These names will be used during cloning the repos.
Since the private keys are protected with strong passphrases, installing a program like keychain will make life easier. keychain stores the decrypted private keys in memory via ssh-agent, so the passphrase only needs to be entered once per session. Without it, every git operation would prompt for the passphrase.
keychain is a wrapper bash script around ssh-agent and ssh-add. I have
been using it for many years without any issues. You can download it from
keychain github page. Download keychain and keychain.1 from keychain github
page, then I install it as follows (or use your distro-specific package
manager)
sudo /bin/cp -fv keychain /usr/local/bin/
sudo chmod +x /usr/local/bin/keychain
sudo /bin/cp -fv keychain.1 /usr/local/share/man/man1
man keychainI do not use bash completion for keychain, you can if you want.
Add the following functions to your ~/.bashrc or ~/.bash_profile:
#====================================================================
# Load ssh keys into ssh-agent via keychain. If the keys are already
# loaded, keychain will not ask for passphrases again. Once loaded,
# ssh-agent holds the decrypted private keys in memory so git
# operations can proceed without re-entering passphrases. Note that
# the decrypted keys exist in memory for the lifetime of the agent.
# If root has access to the system, the keys could potentially be
# extracted from memory.
#====================================================================
load_keys() {
eval $(keychain --eval \
--agents ssh \
id_ed25519_personal \
id_ed25519_work \
id_ed25519_projectx)
}
#====================================================================
# List all keys currently loaded in ssh-agent.
#====================================================================
list_keys() {
keychain --list
}
#====================================================================
# Clear all keys from ssh-agent without stopping the agent.
#====================================================================
clear_keys() {
keychain --clear
}
#====================================================================
# Stop my ssh-agent.
#====================================================================
stop_keys() {
keychain --stop mine
}Whenever I'm in a new terminal and need to work on a project I just type
load_keys. If the keys are already loaded, it does not ask for passphrases.
When I'm done, I type clear_keys. To stop the ssh-agent, I type stop_keys.
I do not add load_keys to my shell's rc file so it does not run every time
I open a terminal. I call it only when I need it.
Whenever in doubt, I just type:
list_keysIf all the keys are not in the list, I type load_keys
Test each account using the Host aliases defined in ~/.ssh/config:
Example:
ssh -T git@github-personalExpected output:
Hi muquit! You've successfully authenticated, but github does not provide shell access.
ssh -T git@github-workExpected output:
Hi muquit2! You've successfully authenticated, but github does not provide shell access.
ssh -T git@github-projectxExpected output:
Hi muquit3! You've successfully authenticated, but github does not provide shell access.
Once ssh is working, make sure to always use ssh URLs when cloning (not HTTPS).
If you see Permission denied (publickey), run load_keys first, then try
again. If it still fails, verify that the public key has been added to the
correct github account
- Use git's conditional includes to automatically set the correct name and email based on the directory. Create a directory structure as follows:
mkdir -p ~/gitdev/work
mkdir -p ~/gitdev/projectxNote: I did not create any directory for personal projects as it is the
default. I can clone personal repos anywhere.
[user]
# personal repos can be cloned anywhere
name = muquit
email = muquit@gmail.com
# work repos
[includeIf "gitdir:~/gitdev/work/"]
path = ~/.gitconfig-work
# another repo
[includeIf "gitdir:~/gitdev/projectx/"]
path = ~/.gitconfig-projectx- Create
~/.gitconfig-workand~/.gitconfig-projectxfiles
~/.gitconfig-work
[user]
name = muquit2
email = muquit@work.example.com~/.gitconfig-projectx
[user]
name = muquit3
email = muquit3@projectxdfdf.comAdd the following alias in ~/.gitconfig
[alias]
whoami = "!echo \"User: $(git config user.name) | Email: $(git config user.email) | Source: $(git config --show-origin user.email | cut -f1)\""To verify which identity is active in the current repository, using the
bash-prompt repo as an example:
➤ cd ~/gitdev/bash-prompt
➤ git whoami
User: muquit | Email: muquit@gmail.com | Source: file:/Users/muquit/.gitconfig➤ cd ~/gitdev/projectx
➤ git whoami
User: projectx | Email: projectx@example.com | Source: file:/Users/muquit/.gitconfig-projectxAlternatively, bash-prompt displays the git username directly in the terminal prompt, so you always know which account is active without running any command. Here is how the prompt looks:
➤ cd ~/gitdev/bash-prompt
[muquit@host]~/gitdev/bash-prompt(main)‹muquit›where ‹muquit› is the git username.
Here is a bash function I use for committing and optionally pushing to gitHub. Before committing, it shows the active git identity via git whoami and a diff summary, then prompts for confirmation. After a successful commit, it prompts whether to push as well. I use it for short commit messages.
#====================================================================
# Bash function to commit and optionally push to github. Before commit
# it displays:
# - Info about git username and git email
# - What files have changed
# And then prompts for commit. After a successful commit, it prompts
# to push to github.
#====================================================================
gcm() {
if [[ -z "$1" ]]; then
echo "Usage: gcm <comment>"
return 1
fi
git whoami
echo ""
git diff --stat
echo ""
read -p "Commit (y/n)? " choice
case "$choice" in
y|Y )
git commit -am "$1" || return 1
;;
n|N )
echo "Commit Aborted"
return 0
;;
* )
echo "Invalid choice, commit aborted"
return 1
;;
esac
echo ""
read -p "Push (y/n)? " push_choice
case "$push_choice" in
y|Y )
git push
;;
n|N )
echo "Push skipped"
;;
* )
echo "Invalid choice, push skipped"
;;
esac
}I will clone my https://github.com/muquit/mailsend-go repo in
~/gitdev/ directory.
cd ~/gitdev
git clone git@github-personal:muquit/mailsend-go.gitImportant: Always use SSH-based URLs (e.g.,
git@github-personal:...) not HTTPS URLs (https://github. com/...). If you clone or add a remote with HTTPS, git will authenticate using your default system credentials (usually your primary account) and ignore the SSH host alias entirely, causing permission errors or commits under the wrong account. If you have an existing repo with an HTTPS remote, fix it with:git remote set-url origin git@github-personal:muquit/mailsend-go.git
Note: the word github-personal because it is used in ~/.ssh/config to map to my
personal github account. example:
Host github-personal
HostName github.com
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519_personal
User git- Run whoami alias
➤ cd mailsend-go
➤ git whoami
User: muquit | Email: muquit@gmail.com | Source: file:/Users/muquit/.gitconfigSimilarly, clone your work or other projects in ~/gitdev/work/
~/gitdev/projectx, ~/gitdev/projectx directories and do not have to worry
about wrong username in commit logs.
If you would like to update information, please do not update README.md
directly. Instead, update docs/README.md. The README.md file is generated
from docs/README.md with a Table of Contents.
MIT License - See LICENSE file for details.
- bash-prompt - A git aware bash prompt
TOC is created by https://github.com/muquit/markdown-toc-go on Feb-22-2026