Two GitHub accounts (personal Cygnus0923, work your-work-account) on one Ubuntu machine, set up 2026-08-29. Prerequisite: ssh-keys-and-github (key generation, ssh-agent, adding keys, cloning); this note covers only the extra work for a second account.

The big picture

YOUR MACHINEGITHUBgithub-personal:OWNER/REPO.gitHost github-personalIdentitiesOnly yespersonal keyid_ed25519_github_personalCygnus0923personal accountgithub-work:OWNER/REPO.gitHost github-workIdentitiesOnly yeswork keyid_ed25519your-work-accountwork account[email protected]:GitHub's default URLno alias matchesIdentitiesOnly skippedevery key SSH knowsoffered in orderfirst match winsmaybe the wrong one
1 Key per account2 Host aliases3 Alias in URL4 Per-repo identity5 Verify
  • GitHub identifies you by SSH key, not username. Two accounts = two keys, and SSH must pick the right one per repo.
  • Left alone, SSH offers keys in order → you silently authenticate as the wrong person.
  • Fix: one key per account + a host alias that pins exactly one key.

1. A separate key per account

ssh-keygen -t ed25519 -C "descriptive-label" -f ~/.ssh/id_ed25519_github_personal
  • -t ed25519 → modern elliptic-curve, shorter and stronger than RSA (legacy).
  • -C → a label only, no functional effect. Name the machine (xuebin@Cygnus-2026-08-29), not your email: it tells you which key to revoke when several machines share an account.
  • Upload only the .pub to GitHub → Settings → SSH and GPG keys. The file without .pub is the private key and never leaves the machine.

Overwrite prompt: there is no undo

ssh-keygen asks before overwriting an existing key. Never answer y without knowing what that key is still used for.

2. Host aliases in ~/.ssh/config

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github_personal
    IdentitiesOnly yes
 
Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes
chmod 600 ~/.ssh/config   # SSH may refuse a config others could write
  • IdentitiesOnly yes is the critical line. Without it SSH offers every key until one is accepted → you’re whichever account matches first. With it, each alias uses exactly one key.
  • chmod 600 matters: a writable config could silently redirect your keys.

3. Rewrite the clone URL to use the alias

The step that catches everyone

GitHub’s URL [email protected]:Cygnus0923/notes-.git matches neither Host block, so IdentitiesOnly never applies and SSH falls back to the default key. Rewrite the host part: github-personal:Cygnus0923/notes-.git.

git remote set-url origin github-personal:OWNER/REPO.git   # fix an existing repo
git clone github-personal:OWNER/REPO.git                   # or clone correctly

4. Per-repo git identity

git config --local user.name  "Xuebin Nam"
git config --local user.email "[email protected]"
git config --global user.useConfigOnly true   # safety net, set once
  • The SSH key controls access; the commit author is separate. If the email isn’t a verified address on that account, GitHub won’t attribute the commit to your profile.
  • useConfigOnly → git refuses to commit in a repo with no identity set, instead of quietly inventing one from your hostname.

Use --local, not --global

A global email silently leaks your personal address onto work commits in any repo where you forget to override it.

5. Verify

ssh -T github-personal     # -> "Hi Cygnus0923!"
ssh -T github-work         # -> "Hi your-work-account!"
git ls-remote origin       # succeeds = remote reachable with the right key

Troubleshooting

SymptomLikely causeCheck / fix
Repository not found (private repo)repo doesn’t exist, or your key’s account can’t see it. GitHub says “not found” instead of “permission denied” so it doesn’t reveal which private repos existcheck which account you authenticated as (ssh -T github-personal) before assuming the repo is missing

Related: git-daily-workflow