Skip to content

muquit/multiple-github-accounts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Table Of Contents

How to use multiple github accounts from a single machine

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.

Generate ssh keys

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_personal

ssh-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.

Add public keys to each github account

  • Login to github with that account
  • Go to Settings -> SSH and GPG keys -> New SSH key
  • Paste the content of the corresponding .pub key file

Note: github does not allow the same public key on multiple accounts. Each account must have a unique key.

Update ~/.ssh/config file

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:

  • User must be git - github always uses git as the ssh user. It identifies the account by the ssh key, not the username.

  • IdentitiesOnly yes - without this, ssh-agent (man ssh-agent for more info) offers all loaded keys and github accepts the first valid one, which may be the wrong account.

  • Host aliases - github-personal, github-work and github-projectx are arbitrary names I chose. These names will be used during cloning the repos.

Install keychain script

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 keychain

I do not use bash completion for keychain, you can if you want.

Start ssh agent with keychain

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.

Verify all keys are loaded

Whenever in doubt, I just type:

    list_keys

If all the keys are not in the list, I type load_keys

Test ssh connections

Test each account using the Host aliases defined in ~/.ssh/config: Example:

ssh -T git@github-personal

Expected output:

Hi muquit! You've successfully authenticated, but github does not provide shell access.
ssh -T git@github-work

Expected output:

Hi muquit2! You've successfully authenticated, but github does not provide shell access.
ssh -T git@github-projectx

Expected 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

Create directory structure

  • 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/projectx

Note: I did not create any directory for personal projects as it is the default. I can clone personal repos anywhere.

Update ~/.gitconfig

Add conditional includes

[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-work and ~/.gitconfig-projectx files

~/.gitconfig-work

[user]
    name = muquit2
    email = muquit@work.example.com

~/.gitconfig-projectx

[user]
    name = muquit3
    email = muquit3@projectxdfdf.com

Add whoami alias

Add 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-projectx

Alternatively, 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.

Commit helper

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
}

Clone repositories

I will clone my https://github.com/muquit/mailsend-go repo in ~/gitdev/ directory.

cd ~/gitdev
git clone git@github-personal:muquit/mailsend-go.git

Important: 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/.gitconfig

Similarly, 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.

How to contribute

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.

License is MIT

MIT License - See LICENSE file for details.

See Also


TOC is created by https://github.com/muquit/markdown-toc-go on Feb-22-2026

About

A guide to using multiple github accounts from a single machine - painless way

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors