2026-01-10 - How I Setup Multiple GitHub Accounts on My Laptop

tl;dr: Use separate SSH keys for authentication and signing, configure SSH hosts with different names, and leverage Git’s conditional config to automatically switch between accounts based on directory.


The Problem

I have two GitHub accounts - let’s call them me (personal) and work (company). I want to:

  1. Use my personal account (me) for all repos on my laptop by default
  2. Use my work account (work) exclusively for repos inside ~/Code/jw/ (my company folder)
  3. Set up SSH keys for both authentication AND commit signing
  4. Have Git automatically use the correct identity based on which folder I’m in

No manual switching, no mistakes, no accidentally committing with the wrong email.

The Solution

The setup involves three main steps:

  1. Generate SSH keys for both accounts (authentication + signing)
  2. Configure SSH to use different keys based on hostname
  3. Configure Git to use different identities based on directory

Let’s walk through each step.

Step 1: Generate SSH Keys

We need four keys total: two for authentication (one per account) and two for signing commits (one per account).

Run these commands to generate all four keys:

# Personal account - authentication
ssh-keygen -t ed25519 -C "hello@hungdoan.xyz" -f ~/.ssh/github_id_me
 
# Work account - authentication
ssh-keygen -t ed25519 -C "hung@jw.com" -f ~/.ssh/github_id_work
 
# Personal account - signing
ssh-keygen -t ed25519 -C "hello@hungdoan.xyz" -f ~/.ssh/github_sign_me
 
# Work account - signing
ssh-keygen -t ed25519 -C "hung@jw.com" -f ~/.ssh/github_sign_work

You’ll be prompted to enter a passphrase for each key. Use a strong passphrase (or the same one for convenience - your choice).

After running these commands, you should have 8 files in ~/.ssh/:

github_id_me          github_id_me.pub
github_id_work        github_id_work.pub
github_sign_me        github_sign_me.pub
github_sign_work      github_sign_work.pub

The .pub files are your public keys (safe to share), and the files without extensions are your private keys (keep them secret!).

Step 2: Configure SSH

Now we need to tell SSH which key to use for which GitHub account. The trick is to use different host aliases.

Open (or create) ~/.ssh/config:

open ~/.ssh/config

Add the following configuration:

# Personal account (default)
Host github.com
  HostName github.com
  PreferredAuthentications publickey
  IdentityFile ~/.ssh/github_id_me
  IdentitiesOnly yes
 
# Work account (use github.com-work as host)
Host github.com-work
  HostName github.com
  PreferredAuthentications publickey
  IdentityFile ~/.ssh/github_id_work
  IdentitiesOnly yes

How This Works

  • When you use git@github.com:..., SSH uses your personal key (github_id_me)
  • When you use git@github.com-work:..., SSH uses your work key (github_id_work)

The IdentitiesOnly yes setting ensures SSH only tries the specified key, not all keys in your ~/.ssh/ folder.

Step 3: Add Public Keys to GitHub

Now we need to upload the public keys to GitHub.

For Your Personal Account

  1. Go to https://github.com/settings/keys
  2. Click “New SSH key”
  3. Choose “Authentication Key” as the key type
  4. Paste the content of your public key:
pbcopy < ~/.ssh/github_id_me.pub
  1. Click “Add SSH key”
  2. Repeat the process for the signing key:
    • Choose “Signing Key” as the key type
    • Paste the content of:
pbcopy < ~/.ssh/github_sign_me.pub

For Your Work Account

Repeat the same process, but:

  1. Log in to your work GitHub account
  2. Upload github_id_work.pub as an Authentication Key
  3. Upload github_sign_work.pub as a Signing Key

Step 4: Configure Git

Now we need to tell Git which identity (name, email, signing key) to use based on the directory.

Main Git Config

Open your main Git config:

open ~/.gitconfig

Add this configuration:

# Load the default config for ALL repositories
[include]
    path = ~/.gitconfig-me
 
# Override with work config for repos inside ~/Code/jw/
[includeIf "gitdir:~/Code/jw/"]
    path = ~/.gitconfig-work
 
# SSH signing configuration (shared by both accounts)
[gpg]
    format = ssh
 
[gpg "ssh"]
    allowedSignersFile = ~/.ssh/allowed_signers

This tells Git:

  1. Use ~/.gitconfig-me as the default for all repos
  2. If the repo is inside ~/Code/jw/, override with ~/.gitconfig-work
  3. Use SSH for GPG signing and reference the allowed signers file

Now create the allowed signers file (we’ll populate it later if you want local verification):

touch ~/.ssh/allowed_signers

Personal Account Config

Create ~/.gitconfig-me:

touch ~/.gitconfig-me
open ~/.gitconfig-me

Add your personal identity and signing configuration:

[user]
    name = Hung Doan
    email = hello@hungdoan.xyz
    signingkey = ~/.ssh/github_sign_me.pub
 
[commit]
    gpgSign = true
 
[tag]
    gpgSign = true
 
[pull]
    ff = true

Work Account Config

Create ~/.gitconfig-work:

touch ~/.gitconfig-work
open ~/.gitconfig-work

Add your work identity and signing configuration:

[user]
    name = Hung Doan
    email = hung@jw.com
    signingkey = ~/.ssh/github_sign_work.pub
 
[commit]
    gpgSign = true
 
[tag]
    gpgSign = true
 
[pull]
    ff = true

Note: You can use a different name for your work account if needed (I kept it the same).

Step 5: Test Your Setup

Let’s verify everything works correctly.

Test Personal Account

Clone a private repo from your personal account (anywhere outside ~/Code/jw/):

cd ~/Code
git clone git@github.com:your-username/your-private-repo.git
cd your-private-repo

Verify your identity:

git config user.email
# Should output: hello@hungdoan.xyz
 
git config user.name
# Should output: Hung Doan

Test Work Account

Clone a private repo from your work account (inside ~/Code/jw/):

cd ~/Code/jw
git clone git@github.com-work:company/work-repo.git
cd work-repo

Verify your identity:

git config user.email
# Should output: hung@jw.com
 
git config user.name
# Should output: Hung Doan (or whatever you set)

Notice we used git@github.com-work:... instead of git@github.com:.... This tells SSH to use the work key.

Important: Cloning Work Repos

When cloning work repos, you need to modify the clone URL to use the github.com-work host:

# GitHub gives you this URL:
git clone git@github.com:company/repo.git
 
# Change it to:
git clone git@github.com-work:company/repo.git

Alternatively, after cloning with the default URL, update the remote:

git remote set-url origin git@github.com-work:company/repo.git

Verifying Commit Signing

Quick Test on GitHub

The easiest way to verify commit signing is to create an empty repo on GitHub and push a test commit:

# Create a new repo on GitHub, then:
mkdir test-signing
cd test-signing
git init
echo "test" > README.md
git add README.md
git commit -m "Test commit signing"
git remote add origin git@github.com:your-username/test-signing.git
git push -u origin main

Check the commit on GitHub - it should show a “Verified” badge next to it.

Verifying Locally (Optional)

If you want to verify signed commits locally with git log --show-signature, you need to populate the allowed_signers file we created earlier.

Without it, running:

git log --show-signature -1

Will show this error:

error: gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification

To enable local verification, add your signing keys to ~/.ssh/allowed_signers:

open ~/.ssh/allowed_signers

1. Copy your personal signing key:

pbcopy < ~/.ssh/github_sign_me.pub

2. Paste it into the file, but move the email to the beginning

The public key format is:

ssh-ed25519 AAAA... hello@hungdoan.xyz

But the allowed_signers format requires the email first:

hello@hungdoan.xyz ssh-ed25519 AAAA...

3. Repeat for your work signing key:

pbcopy < ~/.ssh/github_sign_work.pub

Your final ~/.ssh/allowed_signers file should look like:

hello@hungdoan.xyz ssh-ed25519 AAAA...
hung@jw.com ssh-ed25519 BBBB...

4. Test it:

git log --show-signature -1

You should now see:

Good "git" signature for hello@hungdoan.xyz with ED25519 key SHA256:...

Success! Git can now verify your signed commits locally.

Troubleshooting

Permission Denied (publickey)

If you get this error when cloning:

Permission denied (publickey).
fatal: Could not read from remote repository.

Check:

  1. Did you add the public key to GitHub?
  2. Are you using the correct host (github.com vs github.com-work)?
  3. Test your SSH connection:
ssh -T git@github.com
ssh -T git@github.com-work

Wrong Email in Commits

If commits show the wrong email:

  1. Check which config is being used:
git config --show-origin user.email
  1. Verify the [includeIf] path in ~/.gitconfig matches your directory structure
  2. Make sure you’re inside the correct directory (~/Code/jw/ for work)

Commits Not Signed

If commits aren’t being signed:

  1. Verify signing is enabled:
git config commit.gpgsign
# Should output: true
  1. Check the signing key path:
git config user.signingkey
# Should output: ~/.ssh/github_sign_me.pub (or work variant)
  1. Verify GPG format is set to SSH:
git config gpg.format
# Should output: ssh

Bonus: GitLens Configuration for VSCode/Cursor

If you use VSCode, Cursor, or any editor with GitLens, you’ll notice that links to github.com-work repos won’t work correctly in the GitLens interface. GitLens doesn’t recognize github.com-work as a valid GitHub domain.

To fix this, add a custom remote configuration to your workspace settings.

Create or update .vscode/settings.json in your work project:

{
    "gitlens.remotes": [
        {
            "domain": "github.com-work",
            "type": "Custom",
            "name": "jw",
            "protocol": "https",
            "urls": {
                "repository": "https://github.com/${repo}",
                "branches": "https://github.com/${repo}/branches",
                "branch": "https://github.com/${repo}/commits/${branch}",
                "commit": "https://github.com/${repo}/commit/${id}",
                "file": "https://github.com/${repo}?path=${file}${line}",
                "fileInBranch": "https://github.com/${repo}/blob/${branch}/${file}${line}",
                "fileInCommit": "https://github.com/${repo}/blob/${id}/${file}${line}",
                "fileLine": "#L${line}",
                "fileRange": "#L${start}-L${end}"
            }
        }
    ]
}

This tells GitLens to map the github.com-work domain to the actual GitHub URLs, so all the “Open on GitHub” links and integrations work correctly.

Key Takeaways

  1. Separate keys for auth and signing - While you could use the same key for both, separating them is a security best practice
  2. SSH host aliases - Using github.com-work as an alias lets you route to different keys without changing GitHub’s actual hostname
  3. Conditional Git config - The [includeIf "gitdir:..."] directive is powerful for automatically switching identities
  4. Remember to modify clone URLs - For work repos, use git@github.com-work:... instead of git@github.com:...
  5. GitLens custom remotes - Configure GitLens to recognize your custom SSH host for seamless editor integration

This setup has saved me countless times from accidentally committing with the wrong account. Set it once, forget about it, and let Git handle the rest!


Environment:

  • macOS 14.5
  • Git 2.39+
  • OpenSSH 9.0+

References: