includeIf is a Git config feature that loads another config file only when the repository lives under a certain folder — the cleanest terminal-native way to have two identities on one machine. Organize repositories under folder trees (e.g. ~/code/work/ and ~/code/personal/, or Windows C:/Users/YOU/code/work/), write one small file per identity, and Git automatically applies the right user.name/user.email the moment you cd into a repository. No scripts, no per-repo git config — folder location decides identity, forever.
~/.gitconfig, add [includeIf "gitdir/i:C:/Users/YOU/code/work/"] → path = C:/Users/YOU/.gitconfig-work (repeat for personal). The trailing slash and the i (case-insensitive) matter on Windows. Each included file holds that identity's user.* block.
What includeIf is (in one paragraph)
Git reads your global config (~/.gitconfig) for every command. An includeIf section says: also load this other file — but only if the current repository's directory matches this pattern. Because the match is on the repository's path, repositories under different trees silently inherit different settings. It's a conditional #include at the config level.
Step 1 — sort your repositories into folders
C:/Users/YOU/code/work/ ← all work repositories
C:/Users/YOU/code/personal/ ← all personal repositories
Move existing repositories into these trees (Git doesn't care — history and remotes travel with the folder). Everything you clone from now on goes into the right tree by habit.
Step 2 — create the identity files
# C:/Users/YOU/.gitconfig-work
[user]
name = Work Name
email = me@company.com
# C:/Users/YOU/.gitconfig-personal
[user]
name = Personal Name
email = me@personal.com
Nothing else in these files — keep them single-purpose. Add pull.rebase true or similar only if you want it per tree.
Step 3 — wire the conditions into ~/.gitconfig
# C:/Users/YOU/.gitconfig
[includeIf "gitdir/i:C:/Users/YOU/code/work/"]
path = C:/Users/YOU/.gitconfig-work
[includeIf "gitdir/i:C:/Users/YOU/code/personal/"]
path = C:/Users/YOU/.gitconfig-personal
[user]
name = Fallback Name
email = fallback@example.com
Notes that break half of all first attempts:
- Trailing slash is required —
gitdir/matches directories under the path; without/at the end you'll match nothing. gitdir/i:vsgitdir:— theimakes the match case-insensitive; on Windows drive letters and user paths often differ in case, so keep thei.- Use forward slashes in the pattern even on Windows, or escape backslashes carefully.
- Fallback block last — the global
[user]applies wherever no include matched; set it to something harmless or keep your primary identity there.
Step 4 — verify
cd C:/Users/YOU/code/work/some-repo
git var GIT_AUTHOR_IDENT
# → Work Name <me@company.com> ...
cd C:/Users/YOU/code/personal/other-repo
git var GIT_AUTHOR_IDENT
# → Personal Name <me@personal.com> ...
# confirm which includes fired
git config --show-origin --get-regexp "^user\."
New commits in each tree now carry the right author automatically — GitHub attributes them to the matching account.
What includeIf does NOT fix
| Layer | Handled? | Still needs |
|---|---|---|
| Commit author (identity) | Yes — that's the point | — |
| Push authentication (HTTPS) | No | Per-repo credentials: useHttpPath + one sign-in per repository (see Git Credentials Explained) |
| Push authentication (SSH) | No — but pairs well | One key per account + host aliases; identity applies regardless of which key pushes |
| gh CLI active account | No | gh auth switch --user ... |
includeIf owns the author; the credential layer still needs its own per-repository logic — or a client that binds both.
Troubleshooting
- Nothing changes after edits — re-run from the repository folder; config is read per command, but a wrong pattern silently matches nothing. Test the pattern with
git config --show-origin --get user.email. - Works for one tree, not the other — almost always the trailing slash or drive-letter case; keep
gitdir/i:+ full path +/. - Repos live outside both trees — they get the fallback
[user]; either widen the patterns or accept the default. - Submodules — submodule paths are matched too; keep them inside the same tree as their parent.
The zero-config version
includeIf is the right tool if you want terminal-native, transparent, versionable config. If you'd rather not think about folders, identity files, and credential entries at all: GITmaxed gives you the same outcome without any of it — every account stays signed in, each repository has an explicit account binding, and commits are authored as that account. Folder trees taught you the model; a multi-account client just enforces it.
Related questions answered (the same queries, one by one)
How do I use different git user.name and user.email per project?
Either set them per repository (git config user.name without --global) or, at scale, use includeIf folder rules so identity follows the repository's location automatically.
What does gitdir/i mean in git config?
gitdir/ matches repositories under a directory (trailing slash required); /i makes the comparison case-insensitive — important on Windows.
Why is my includeIf not matching anything on Windows?
Usually a missing trailing slash, backslash-vs-forward-slash mismatch, or drive-letter case difference. Use gitdir/i: with forward slashes and a trailing /.
Does includeIf change which account pushes?
No — it only changes config (identity). Pushes still use whatever credential (HTTPS) or SSH key the repository's URL points at; combine with per-repo credentials or per-account keys.
Is includeIf better than editing user.email per repository?
For many repositories organized by account, yes — one-time setup, automatic forever, and new clones inherit it from their folder. For two repos, per-repo config is fine.
Can includeIf load different SSH keys per folder?
Yes — via core.sshCommand in each included file (e.g. ssh -i ~/.ssh/id_ed25519_work -o IdentitiesOnly=yes), though host aliases in ~/.ssh/config are usually cleaner.
Is there a GUI alternative to setting up includeIf?
Yes — GITmaxed binds accounts to repositories directly in the app, producing the same per-repository identity without folder-based config files.
No comments:
Post a Comment