Managing Multiple GitHub Accounts on One Machine
Running both personal and work projects on one dev machine, with commits going to different GitHub accounts. Don’t want to manually change
user.emailafter every clone, and don’t want a global account-switching script. SSH key isolation + Git conditional config solves it once and for all.
1. Scenario
Typical needs:
- Personal projects (
~/personal/*) commit with personal GitHub account - Work projects (
~/work/*) commit with company GitHub account - Each account has its own SSH key, no interference
- Identity switches automatically when entering different directories, no manual setup
Additional pain points:
- Corporate network might block SSH default port 22, need to use 443
- Some projects need aliases (like
work.github.com) to differentiate remote URLs
2. Overall Strategy
Three-layer configuration working together:
- SSH layer (
~/.ssh/config): Configure separate keys and Host aliases for different accounts - Git global layer (
~/.gitconfig): Set default account and SSH command - Git conditional layer (
~/.gitconfig-work): Auto-override account info based on directory path
Key mechanism: includeIf lets Git load additional config files in specific directories.
3. Steps
3.1 Generate SSH Key Pairs
Generate independent keys for each account:
# Personal account key
ssh-keygen -t rsa -b 4096 -C "personal@example.com" -f ~/.ssh/id_rsa_personal
# Work account key
ssh-keygen -t rsa -b 4096 -C "work@company.com" -f ~/.ssh/id_rsa_work
After generation you’ll have:
~/.ssh/id_rsa_personal+~/.ssh/id_rsa_personal.pub~/.ssh/id_rsa_work+~/.ssh/id_rsa_work.pub
Add the .pub public keys to the SSH keys settings page of the corresponding GitHub accounts.
3.2 Configure SSH Host Aliases
Edit ~/.ssh/config (create if it doesn’t exist):
# Personal account (default)
Host github.com
HostName ssh.github.com
User git
IdentityFile ~/.ssh/id_rsa_personal
Port 443
# Work account (using alias work.github.com)
Host work.github.com
HostName ssh.github.com
User git
IdentityFile ~/.ssh/id_rsa_work
Port 443
Key points:
- Port 443: Bypass firewall blocking of port 22, GitHub officially supports
ssh.github.com:443 - Host alias:
work.github.comis a local alias, actual connection is still tossh.github.com - IdentityFile: Specify which key to use
Test connections:
# Test personal account
ssh -T git@github.com
# Expected output: Hi personal-username! You've successfully authenticated...
# Test work account
ssh -T git@work.github.com
# Expected output: Hi work-username! You've successfully authenticated...
3.3 Configure Git Global Defaults
Edit ~/.gitconfig:
[user]
name = Your Name
email = personal@example.com
[core]
# Globally force use of personal account key
sshCommand = ssh -i ~/.ssh/id_rsa_personal -F /dev/null
# Conditional config: work directory auto-switches account
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
Key points:
sshCommandforces use of specified key,-F /dev/nullprevents~/.ssh/configinterference (optional, depends on your priority strategy)includeIfpath matching: the path aftergitdir:must end with/to match subdirectories- Path supports
~expansion and wildcards*
3.4 Configure Work Account Conditional File
Create ~/.gitconfig-work:
[user]
name = Your Name
email = work@company.com
[core]
sshCommand = ssh -i ~/.ssh/id_rsa_work -F /dev/null
Now the logic is:
- Default uses personal account (
~/.gitconfig) - Entering any subdirectory of
~/work/, auto-switch to work account (~/.gitconfig-workoverrides)
3.5 Clone Work Projects Using Host Alias
When cloning work projects, modify the URL:
# Original URL (would use personal account)
git clone git@github.com:company/project.git
# Use Host alias (will use work account key)
git clone git@work.github.com:company/project.git
Or modify remote after cloning:
git remote set-url origin git@work.github.com:company/project.git
Why need alias?
Even in ~/work/ directory, if remote URL is git@github.com, SSH will prioritize matching the Host github.com config in ~/.ssh/config. Host aliases let you differentiate accounts at the URL level.
4. Verify Configuration
4.1 Check Active Config in Current Directory
# In personal project directory
cd ~/personal/my-project
git config user.email
# Output: personal@example.com
# In work project directory
cd ~/work/company-project
git config user.email
# Output: work@company.com
4.2 Check SSH Key Being Used
# View actual SSH command in use
git config core.sshCommand
# Manual test (with verbose logging)
GIT_SSH_COMMAND="ssh -v" git ls-remote origin
# Output will show "Offering public key: /path/to/id_rsa_xxx"
4.3 Test Commit Identity
# Create test commit
echo "test" > test.txt
git add test.txt
git commit -m "test commit"
# View commit author
git log -1 --format="%an <%ae>"
5. Common Issues
5.1 Port 22 Blocked
Symptom: ssh -T git@github.com times out
Solution: Add to ~/.ssh/config:
Host github.com
HostName ssh.github.com
Port 443
GitHub officially provides SSH service on port 443 at ssh.github.com, specifically for bypassing firewalls.
5.2 Key Permission Issues
Symptom: Permissions 0644 for 'id_rsa_work' are too open
Solution:
chmod 600 ~/.ssh/id_rsa_*
chmod 644 ~/.ssh/id_rsa_*.pub
Private keys must be readable/writable only by owner (600), public keys can be more permissive (644).
5.3 includeIf Not Taking Effect
Checklist:
- Path must end with
/:gitdir:~/work/(correct) vsgitdir:~/work(wrong) - Git version:
includeIfrequires Git 2.13+, rungit --versionto confirm - Path expansion:
~expands, but relative paths don’t, recommend absolute paths or~/ - Debug: Run
git config --show-origin user.emailto see config source
5.4 Switching Account for Existing Projects
If project has already committed with wrong account:
# 1. Modify remote URL (if needed)
git remote set-url origin git@work.github.com:company/project.git
# 2. Modify most recent commit author (if not yet pushed)
git commit --amend --reset-author
# 3. Batch modify historical commits (use with caution, rewrites history)
git filter-branch --env-filter '
if [ "$GIT_COMMITTER_EMAIL" = "wrong@example.com" ]; then
export GIT_COMMITTER_EMAIL="correct@example.com"
export GIT_AUTHOR_EMAIL="correct@example.com"
fi
' --tag-name-filter cat -- --branches --tags
6. Advanced: Finer-Grained Control
6.1 Project-Specific Configuration
If a project needs special configuration, run within the project:
git config user.email "special@example.com"
git config core.sshCommand "ssh -i ~/.ssh/id_rsa_special"
Project-level config (.git/config) has highest priority, overrides global and conditional configs.
6.2 Multiple Work Directories
If you have multiple work directories:
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
[includeIf "gitdir:~/company-a/"]
path = ~/.gitconfig-company-a
[includeIf "gitdir:~/company-b/"]
path = ~/.gitconfig-company-b
6.3 HTTPS Protocol Multi-Account
This article focuses on SSH, but HTTPS also supports multi-account:
- macOS Keychain stores credentials, managed by
git-credential-osxkeychain - Or use GitHub CLI:
gh auth loginsupports multi-account switching - Conditional config can set different
credential.helper
7. Summary
Workflow after configuration:
- Personal projects in
~/personal/, auto-use personal account - Work projects in
~/work/, auto-use work account - Remember to use
git@work.github.comwhen cloning work projects - Forgot to configure? Check with
git config user.emailbefore committing
Core benefits:
- Zero manual switching: Automatic upon entering directory
- Thorough isolation: Keys, identity, directories three-layer isolation
- Verifiable: Clear testing methods for each step
This setup has been in use for two years, never had a commit with the wrong account since.