Managing multiple GitHub identities (personal, work, org accounts) requires:
The old setup used includeIf "gitdir:"= blocks in =~/.gitconfig, requiring a new block for each directory where repos lived.
Instead of a monolithic ~/.ssh/config, use:
~/.ssh/
├── config # just "Include profiles/*"
└── profiles/
├── personal
├── work
├── org1
└── org2
Each profile file contains:
Host p1
HostName ssh.github.com
Port 443
User personal-user
IdentityFile ~/.ssh/id_personal
The ~/.gitconfig now has two parts:
Maps GitHub usernames to SSH host aliases:
[url "git@p1:personal-user/"]
insteadOf = "https://github.com/personal-user/"
insteadOf = "[email protected]:personal-user/"
This allows cloning with regular GitHub URLs while automatically using the correct SSH key.
UPDATE 2026-01-06: Changed from URL-based matching to directory-based matching.
Instead of matching by remote URL, match by repository directory:
[includeIf "gitdir:~/dev/personal/"]
path = ~/.config/git/profiles/personal
[includeIf "gitdir:~/dev/work/"]
path = ~/.config/git/profiles/work
This approach organizes repositories by profile in the filesystem, making identity selection explicit and reliable.
Profile files live in ~/.config/git/profiles/ and contain only user info:
[user]
name = "Your Name"
email = "[email protected]"
git clone https://github.com/username/repo uses the correct key automatically~/.ssh/profiles/ and ~/.config/git/profiles/, and a gitdir includegitdir include per profile covers all repos in that directory tree| Purpose | Location |
|---|---|
| SSH profiles | ~/.ssh/profiles/* |
| Git profiles | ~/.config/git/profiles/* |
| Main git config | ~/.gitconfig |
| Main SSH config | ~/.ssh/config |
All repositories should store HTTPS URLs in their .git/config:
[remote "origin"]
url = https://github.com/username/repo.git
The URL rewriting rules in ~/.gitconfig automatically convert these to SSH at runtime:
$ git remote get-url origin git@alias:username/repo.git
This means:
.git/config): https://github.com/username/repo.gitgit@alias:username/repo.gitPrevious approach: Used hasconfig:remote.*.url:git@alias:*/** to match repositories by remote URL.
Problem discovered: The hasconfig condition checks the URL stored in .git/config before URL rewriting happens. Since repositories store HTTPS URLs (https://github.com/username/...), the pattern looking for SSH aliases (git@alias:*/**) never matched.
Solution: Changed to directory-based matching using gitdir:/path/to/profile/. This approach:
Migration steps:
includeIf conditions from hasconfig:remote.*.url: to gitdir: patternsuser.name and user.email configs from individual repositories~/.gitconfig to group each profile’s URL rewriting and includeIf togetherExample =~/.gitconfig= structure:
# Profile configurations - grouped by profile, sorted alphabetically
# profile1 (personal)
[url "git@p1:personal-user/"]
insteadOf = "https://github.com/personal-user/"
insteadOf = "[email protected]:personal-user/"
[includeIf "gitdir:~/dev/personal/"]
path = ~/.config/git/profiles/profile1
# profile2 (work)
[url "git@p2:work-user/"]
insteadOf = "https://github.com/work-user/"
insteadOf = "[email protected]:work-user/"
[includeIf "gitdir:~/dev/work/"]
path = ~/.config/git/profiles/profile2