When you push to GitHub with Git, SSH picks one key behind the scenes and authenticates with it. Day to day, one key is enough, so you rarely think about which key is in use.
When you need another account, you have to present a different key to the same github.com. If you handle that loosely, you can land on the wrong account, or the name recorded on commits can drift from the account you authenticated as.
First we’ll look at how SSH chooses a key, then connect that to a Host alias for the other account and to includeIf, which switches the commit author by folder.
Terms
SSH key
A private-key and public-key pair. The private key lives on the Mac; the public key lives on GitHub. The Mac presents the public key, GitHub confirms it is registered, asks for a signature on a challenge, verifies that signature with the public key, and that is how it decides which account you are.
Host alias
A connection name you write in ~/.ssh/config for your own use. It is not a real server name. Combined with HostName github.com, it means “when I connect under this name, use this key.” The name for the other account is github-other.
IdentityFile
The path of the private key SSH will present. Candidates come, in order, from IdentityFile in ~/.ssh/config, keys loaded in ssh-agent, and default names such as ~/.ssh/id_ed25519.
includeIf
A Git mechanism that loads config when a local directory condition matches. What you put in gitdir: is a folder on your PC, not a path on GitHub. Here it is used to switch the commit author (user.name / user.email).
Commit author
The user.name and user.email recorded on a commit. That is independent of SSH authentication (which GitHub account you push as). Even if you push with the other account’s key, the author stays your usual name if Git config is still the usual one.
How SSH authentication works
On the Mac you have a private key and a public key.
~/.ssh/id_ed25519 ← private key
~/.ssh/id_ed25519.pub ← public key
Once you register the public key on the GitHub account you normally use, GitHub ties that key to that account. There is no direct definition on the Mac that says “id_ed25519 = this account.”
Mac → presents the public key → GitHub confirms registration → sign the challenge → the account is decided
[On connect] Mac → GitHub
Mac: “I’ll present a public key first. I’ll offer candidate keys in order.”
[On connect] GitHub
GitHub: “That public key is registered. Sign this. This key belongs to the usual account. Hi username!”
The Mac is not sending an account name. It presents public keys, and only the key that is accepted is used to sign with the private key. GitHub checks each presented public key one at a time and, if it is registered, verifies the signature. It is not the account side walking through its registered keys in order.
Who tries keys in order?
It can feel like “after the signature is sent to GitHub, GitHub walks through registered public keys in order.” The side that mainly tries keys in order is the SSH client on the Mac.
| Side | What it does |
|---|---|
| Mac (SSH client) | Presents candidate keys in order: config → ssh-agent → id_ed25519, and so on |
| GitHub | For the one public key that was presented, checks “is it registered?”, and if so runs challenge → signature verification |
GitHub does not “walk every key registered on other accounts.” For the one public key the Mac handed over, it looks it up in the DB and scores a hit. GitHub does not know up front whether you want the usual account or the other account. Which public key was presented is all that decides the account.
If the first key is unregistered, GitHub rejects it and the Mac presents the next key. Authentication ends at the moment one is accepted.
Mac: presents public key A (Offering public key)
GitHub: A is unregistered → reject
Mac: presents public key B
GitHub: B is registered → return a challenge
Mac: signs with private key B
GitHub: verifies with public key B → OK → Hi username!
The private key itself is never sent. The public key goes out first, and only the accepted key does the signature exchange.
To confirm:
ssh -T git@github.com
On success you see the username GitHub recognized, like Hi USERNAME! You've successfully authenticated....
Why id_ed25519 is used
SSH does not brute-force every file under ~/.ssh. Key candidates mainly come from the following.
IdentityFilein~/.ssh/config- Keys loaded in
ssh-agent - Standard default key names such as
~/.ssh/id_ed25519and~/.ssh/id_rsa
id_ed25519 is not a GitHub-only name; it is a standard default key name for SSH. You may already have the same key registered on other services, such as GitLab or a server you run yourself.
To see which keys are candidates:
ssh -G github.com | grep -i identityfile
Which keys were actually offered, and which one was accepted, you can see in a verbose log.
ssh -vT git@github.com
To pull out only the key-related lines:
ssh -vT git@github.com 2>&1 | grep -E "Offering public key|Server accepts key"
Offering public key is a candidate that was presented. Server accepts key is the key GitHub accepted.
sequenceDiagram
participant SSH as SSH client
participant GH as GitHub
SSH->>SSH: ① Gather key candidates<br/>config / agent / default names
SSH->>GH: ② Offering public key
GH->>GH: ③ Match the public key
GH-->>SSH: ④ Server accepts key
Note over GH: ⑤ The account is decided
Figure: SSH presents candidate keys, and GitHub’s public-key match decides the account.
SSH setup for multiple accounts
The approach is leave the usual account as the default, and add an exception only for the other account. Keep the existing id_ed25519 as-is.
Create a key for the other account
ssh-keygen -t ed25519 -C "OTHER_ACCOUNT_EMAIL" -f ~/.ssh/id_ed25519_github_other
What you get:
~/.ssh/id_ed25519_github_other ← private key
~/.ssh/id_ed25519_github_other.pub ← public key
Copy the public key on macOS.
pbcopy < ~/.ssh/id_ed25519_github_other.pub
On the other GitHub account, paste it under Settings → SSH and GPG keys.
Add a Host alias in ~/.ssh/config
You do not have to spell out the usual-account side. Add only the other account.
Host github-other
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github_other
IdentitiesOnly yes
github-other is not a real server; it is a Host alias you chose. The actual destination is HostName github.com.
The git in User git is not a GitHub account name. For SSH to GitHub the SSH username is fixed as git, and whether you are the usual account or the other account is decided by the key you present.
IdentitiesOnly yes tells SSH not to try other keys loaded in the agent first. That avoids the default key succeeding first when you connect under the alias.
What happens when you authenticate as github-other
For ssh -T git@github-other or git push (when the remote is git@github-other:...), the Mac reads ~/.ssh/config and takes only the github-other key as a candidate. Because IdentitiesOnly yes is set, it does not offer the usual key from ssh-agent first.
[When running ssh -T git@github-other] Mac
I’ll read config. Host is
github-other, the key to use is onlyid_ed25519_github_other.IdentitiesOnly yes, so I won’t offer agent keys.
[Same moment] Mac → GitHub
Presenting public key
id_ed25519_github_other(Offering public key)
[Same moment] GitHub
That public key is registered on the other account. Here’s a challenge — sign it.
[Same moment] Mac → GitHub
Signed with private key
id_ed25519_github_other
[Same moment] GitHub
Signature OK. Hi other-user! Authenticated as the other account.
git push is the same. If the remote is git@github-other:OTHER_ACCOUNT/my-repo.git, every push connects via github-other over SSH, and only the same key is used.
git remote -v
# origin git@github-other:OTHER_ACCOUNT/my-repo.git (push)
git push
# internally: SSH to git@github-other → authenticate with id_ed25519_github_other
An example of checking with a verbose log:
ssh -vT git@github-other 2>&1 | grep -E "Offering public key|Server accepts key|Authenticated to"
The output looks like this (the fingerprint differs per environment).
debug1: Offering public key ED25519 SHA256:xxxxxxxx ... id_ed25519_github_other
debug1: Server accepts key: ... id_ed25519_github_other
Authenticated to github.com ([140.82.121.4]:22) using "publickey".
Hi other-user! You've successfully authenticated, but GitHub does not provide shell access.
There is only one Offering public key line because IdentitiesOnly yes narrowed the candidates to one key. The usual id_ed25519 does not appear.
On the other hand, if IdentitiesOnly yes is missing and the usual key is loaded in the agent, even a Host meant for the other account can offer id_ed25519 first and authenticate as the usual account.
debug1: Offering public key ED25519 SHA256:aaaaaaaa ... id_ed25519
debug1: Server accepts key: ... id_ed25519
Hi default-user! ...
When the symptom is “this is the other account’s repository, but I have no push permission,” a quick check is whether the remote Host is github-other and whether IdentitiesOnly yes is set.
To confirm authentication:
# usual account
ssh -T git@github.com
# other account
ssh -T git@github-other
The end mapping looks like this.
github.com → ~/.ssh/id_ed25519 → usual account
github-other → ~/.ssh/id_ed25519_github_other → other account
[When connecting as the other account] Mac → GitHub
Mac: “
github-other, so I’ll present onlyid_ed25519_github_other.”
[When connecting as the other account] GitHub
GitHub: “That public key is tied to the other account. Signature OK. Hi other-user!”
Clone a repository for the other account
The usual SSH URL GitHub shows is this.
git@github.com:OTHER_ACCOUNT/repo.git
To authenticate as the other account, change the Host part to the alias.
git clone git@github-other:OTHER_ACCOUNT/repo.git
Here OTHER_ACCOUNT is the repository owner. It is not a specifier for the authenticating user. The authenticating account is decided by the SSH key.
After you clone, that URL is stored as remote origin.
git remote -v
origin git@github-other:OTHER_ACCOUNT/repo.git (fetch)
origin git@github-other:OTHER_ACCOUNT/repo.git (push)
From then on, ordinary git fetch / git pull / git push will use the other account’s key.
To switch the remote on an existing repository:
git remote set-url origin git@github-other:OTHER_ACCOUNT/repo.git
The same applies to private repositories. If you can clone, at least SSH authentication and read permission for the other account have succeeded. If you do not have write permission, clone can succeed and push will still fail.
HTTPS is a different path
git clone https://github.com/OTHER_ACCOUNT/repo.git
also works, but that is HTTPS authentication, not SSH.
OTHER_ACCOUNT in the URL is the repo owner. It is not a specifier that authenticates you as the other account. For a private repository, HTTPS-side credentials are used — a Personal Access Token, Git Credential Manager, macOS Keychain, and so on.
So the SSH setup so far:
github.com → usual account
github-other → other account
does not apply to https://github.com/.... If you clone via HTTPS from GitHub’s green button, the ~/.ssh/config branch never runs.
Put together, there are two authentication paths.
Authentication to GitHub
├─ SSH → SSH key (github.com / github-other)
└─ HTTPS → credential / token
Commit author
└─ Git config → user.name / user.email
Switch the commit author by folder
Even if you clone with the other-account URL, the commit author does not switch automatically. If global user.name / user.email are the usual account, you get this mismatch.
Push authentication to GitHub → other account
Commit author → usual account
To check:
git config user.name
git config user.email
In a local folder for the other account, switch the Git author there as well.
As an example, put other-account repositories under ~/work/github-other/.
~/work/
├── repo-default/
└── github-other/
├── repo-1/
├── repo-2/
└── nested/repo-3/
Other-account settings in ~/.gitconfig-other:
[user]
name = OTHER_NAME
email = OTHER_EMAIL
Main ~/.gitconfig:
[user]
name = DEFAULT_NAME
email = DEFAULT_EMAIL
[includeIf "gitdir:~/work/github-other/"]
path = ~/.gitconfig-other
That splits things like this.
~/work/repo-default/ → usual-account author
~/work/github-other/repo-1/ → other-account author
~/work/github-other/repo-2/ → other-account author
~/work/github-other/nested/... → other-account author
gitdir:~/work/github-other/ is a local path on your PC, not a path on GitHub. If you specify the parent folder, it applies to Git repositories under it.
You can see which file a value was read from with:
git config user.name
git config user.email
git config --show-origin --get user.email
includeIf does not switch SSH authentication
For example, the following keeps the folder as other-account, but the SSH Host stays github.com.
cd ~/work/github-other
git clone git@github.com:OTHER_ACCOUNT/repo.git
The usual account’s key is used. To clone as the other account, you still need the Host alias as before.
git clone git@github-other:OTHER_ACCOUNT/repo.git
The roles are completely separate.
~/.ssh/config
→ decides the SSH authentication account for GitHub
→ which public key / private key to use
Git config / includeIf
→ decides the user.name / user.email recorded on a commit
→ the repository's commit author
Typical work on the other account looks like this.
cd ~/work/github-other
git clone git@github-other:OTHER_ACCOUNT/repo.git
cd repo
git config user.name
git config user.email
git remote -v
The state you want:
user.name / user.email → other account
origin → git@github-other:OTHER_ACCOUNT/repo.git
From then on, ordinary git commit / git push makes both the commit author and GitHub authentication the other account.
sequenceDiagram
participant SSH as SSH
participant GH as GitHub
participant Git as Git
rect rgba(120, 140, 180, 0.1)
Note over SSH,GH: SSH authentication
SSH->>GH: ① github.com uses id_ed25519
GH-->>SSH: ② Usual account
SSH->>GH: ③ github-other uses the other key
GH-->>SSH: ④ Other account
end
rect rgba(120, 160, 130, 0.1)
Note over Git: Commit author
Git->>Git: ⑤ global is the usual author
Git->>Git: ⑥ includeIf gitdir is the other author
end
Figure: The SSH Host and Git includeIf are separate layers. Only when both are in place do authentication and author become the other account.
Takeaways
- SSH authentication to GitHub works by the Mac presenting a public key, and GitHub verifying registration and the signature to decide the account. What is tried in order is the Mac’s candidate keys; GitHub does not walk every registered key.
- Key candidates are
~/.ssh/config,ssh-agent, and default names such asid_ed25519. Keep the existing default key; it may already be in use on other services. - For the other account, add a separate key and a Host alias (
github-other). Change the Host in the clone URL to the alias, and that remote is used for later push / pull. - SSH config does not apply to
https://github.com/.... HTTPS is the token / credential path. - The commit author is
user.name/user.email. You can switch it per folder withincludeIf, but that does not switch SSH authentication.