This guide shows a clean way to use Git with:
- multiple Git hosting services such as GitHub and GitLab
- different SSH keys for each host
- different Git email addresses per host or account
All examples use placeholder names only. Replace them with your own hostnames, paths, usernames, and email addresses.
Use SSH to choose the key by host, and use Git config to choose the email by remote URL.
That split keeps the setup predictable:
- SSH decides which private key to use
- Git decides which author identity to use
Create one key per host or account.
Examples:
ssh-keygen -t ed25519 -f ~/.ssh/github_personal_ed25519 -C "github-personal"
ssh-keygen -t ed25519 -f ~/.ssh/gitlab_work_ed25519 -C "gitlab-work"This gives you:
~/.ssh/github_personal_ed25519~/.ssh/github_personal_ed25519.pub~/.ssh/gitlab_work_ed25519~/.ssh/gitlab_work_ed25519.pub
Add each public key to the correct Git host account.
Examples:
- add
github_personal_ed25519.pubto your GitHub account - add
gitlab_work_ed25519.pubto your GitLab account
Put host rules in ~/.ssh/config.
Example for one GitHub account and one GitLab account:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_personal_ed25519
IdentitiesOnly yes
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/gitlab_work_ed25519
IdentitiesOnly yesWhy this matters:
IdentityFileselects the key for that hostIdentitiesOnly yesprevents SSH from trying unrelated keys first
If your network blocks SSH on port 22, you can override host and port.
Example for GitLab over port 443:
Host gitlab.com
HostName altssh.gitlab.com
User git
Port 443
IdentityFile ~/.ssh/gitlab_work_ed25519
IdentitiesOnly yesStart an agent and load the keys:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/github_personal_ed25519
ssh-add ~/.ssh/gitlab_work_ed25519Verify:
ssh-add -lIf you want the keys loaded automatically on login, configure that using your desktop environment or shell startup files.
Test each host directly before using Git:
ssh -T git@github.com
ssh -T git@gitlab.comIf one host fails here, fix SSH first. Do not debug Git until direct SSH works.
Clone repositories using SSH URLs, not HTTPS URLs.
Examples:
git clone git@github.com:example-org/example-repo.git
git clone git@gitlab.com:example-group/example-repo.gitCheck an existing remote:
git remote -vChange an existing repo from HTTPS to SSH:
git remote set-url origin git@github.com:example-org/example-repo.gitUse Git conditional includes based on the repo remote URL.
This works better than directory-based rules when repositories move around, such as inside containers or different workspaces.
In ~/.gitconfig:
[user]
name = Example Name
useConfigOnly = true
[includeIf "hasconfig:remote.*.url:git@github.com:**"]
path = ~/.gitconfig-github
[includeIf "hasconfig:remote.*.url:https://github.com/**"]
path = ~/.gitconfig-github
[includeIf "hasconfig:remote.*.url:git@gitlab.com:**"]
path = ~/.gitconfig-gitlab
[includeIf "hasconfig:remote.*.url:ssh://git@gitlab.com/**"]
path = ~/.gitconfig-gitlab
[includeIf "hasconfig:remote.*.url:https://gitlab.com/**"]
path = ~/.gitconfig-gitlabIn ~/.gitconfig-github:
[user]
email = github-user@example.invalidIn ~/.gitconfig-gitlab:
[user]
email = gitlab-user@example.invalidNotes:
user.useConfigOnly = truemakes Git fail instead of silently using the wrong email- the email is selected per repository based on its remote URL
- you can still override it in a single repository with local config if needed
Check which email a repository will use:
git -C /path/to/repo config user.email
git -C /path/to/repo config --show-origin --get-regexp '^user\.(name|email)$'If you use more than one account on the same host, define SSH aliases.
Example with two GitHub accounts:
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/github_personal_ed25519
IdentitiesOnly yes
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/github_work_ed25519
IdentitiesOnly yesThen use those aliases in the remote URL:
git clone git@github-personal:example-user/example-repo.git
git clone git@github-work:example-org/example-repo.gitIf you want different emails for those aliases too, extend ~/.gitconfig:
[includeIf "hasconfig:remote.*.url:git@github-personal:**"]
path = ~/.gitconfig-github-personal
[includeIf "hasconfig:remote.*.url:git@github-work:**"]
path = ~/.gitconfig-github-workThen create the matching files:
~/.gitconfig-github-personal
[user]
email = personal@example.invalid~/.gitconfig-github-work
[user]
email = work@example.invalidSSH is strict about permissions.
Use:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/*_ed25519
chmod 644 ~/.ssh/*.pubMake sure the relevant host entry includes:
IdentitiesOnly yes
IdentityFile ~/.ssh/your_expected_keyThen retry:
ssh -T git@github.comCheck which config file is winning:
git config --show-origin --get-regexp '^user\.(name|email)$'Then inspect the remote:
git remote -vIf needed, set the email only for that repository:
git config user.email repo-specific@example.invalidTest both hosts directly:
ssh -T git@github.com
ssh -T git@gitlab.comIf one fails and the other succeeds, the problem is almost always one of:
- the wrong key is assigned to that host
- the public key was added to the wrong account
- the host needs a custom port or hostname
- the key was not loaded into
ssh-agent
If the remote is HTTPS, SSH key selection does not apply.
Convert it to SSH:
git remote set-url origin git@github.com:example-org/example-repo.gitThe stable pattern is:
- one SSH key per host or account
- host rules in
~/.ssh/config - SSH remotes for repositories
- conditional Git includes based on remote URL
- optional host aliases for multiple accounts on the same service
That keeps authentication and author identity separate, which is the easiest setup to maintain.