Git IncludeIf: Elegantly Managing Multiple Git Identities
As a developer, have you ever experienced the awkwardness of accidentally committing code to a company project with your personal email? Or exposing your work email in an open-source project? If you maintain both work and personal projects, manually switching Git configurations is not only cumbersome but also prone to errors.
Fortunately, Git provides a powerful and elegant solution: includeIf. This feature allows Git to automatically load different configuration files based on different conditions, completely solving the problem of multi-identity management.
Why Do We Need includeIf?
In daily development, we often need to switch between different identities:
- Work projects: Using a company email (
work@example.com), company GPG signing key, company SSH key - Personal projects: Using a private email (
personal@example.com), personal GPG key, personal SSH key - Open-source contributions: Possibly another set of configurations
Without includeIf, you would need to:
- Remember to run
git config user.email xxx@xxx.comevery time you switch projects. - Or manually set local configurations in each repository.
- Repeatedly check if the correct identity is being used before committing.
This manual approach is not only troublesome but also extremely error-prone. Once you commit with the wrong identity and push to the remote repository, it can be very difficult to fix.
What is includeIf?
includeIf is a conditional configuration inclusion feature introduced in Git 2.13 (May 2017). It allows you to automatically load different configuration files based on specific conditions (such as repository path, remote URL, current branch, etc.).
The basic syntax is as follows:
[includeIf "condition"]
path = path/to/config/file/to/includeWhen Git reads the configuration, it evaluates the condition. If the condition is met, the content of the specified configuration file will be included, and its configurations will override previous settings.
Common includeIf Conditions
1. Based on Directory Path (gitdir)
This is the most commonly used method, determining which configuration to use based on the repository’s directory:
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
[includeIf "gitdir:~/personal/"]
path = ~/.gitconfig-personalNotes:
- The trailing
/in the path is important!~/work/will match all subdirectories within that directory. - If written as
~/work(without the slash), it will only precisely match this path. - The tilde
~will automatically expand to the user’s home directory.
2. Case-Insensitive Path Matching (gitdir/i)
Especially useful on Windows systems:
[includeIf "gitdir/i:C:/Work/"]
path = C:/Users/username/.gitconfig-work3. Based on Branch Name (onbranch)
Loads configuration based on the current branch:
[includeIf "onbranch:main"]
path = ~/.gitconfig-main4. Based on Remote URL (hasconfig:remote.*.url) ⭐
This is a powerful feature introduced in Git 2.36 (April 2022) that allows configuration to be determined based on the repository’s remote URL. This is also the focus of this article.
[includeIf "hasconfig:remote.*.url:https://github.com/**"]
path = ~/.gitconfig-github
[includeIf "hasconfig:remote.*.url:https://gitlab.company.com/**"]
path = ~/.gitconfig-workPractical Example: Using hasconfig:remote.*.url to Distinguish Identities
Now let’s look at a complete configuration example demonstrating how to elegantly manage both work and personal identities.
Main Configuration File ~/.gitconfig
[core]
autocrlf = input
[commit]
gpgsign = true
[gpg]
format = ssh
[includeIf "hasconfig:remote.*.url:work:<name>/**"]
path = /home/nite/.ssh/work.gitconfig
[includeIf "hasconfig:remote.*.url:personal:<name>/**"]
path = /home/nite/.ssh/personal.gitconfigHere, work:<name> and personal:<name> use Git’s URL alias feature.
Work Configuration ~/.gitconfig-work
[user]
name = "Your Work Name"
email = "work@example.com"
signingKey = "~/.ssh/id_work.pub"
[commit]
gpgsign = true
[core]
sshCommand = "ssh -i ~/.ssh/id_work -o IdentitiesOnly=yes"This configuration file will automatically take effect when you operate company GitLab repositories, including:
- Work email
- Work SSH signing key
- Forced GPG signing
- Specifies the use of a dedicated work SSH key for authentication
Personal Configuration ~/.gitconfig-personal
[user]
name = "Your Personal Name"
email = "personal@example.com"
signingKey = "~/.ssh/id_personal.pub"
[commit]
gpgsign = false
[core]
sshCommand = "ssh -i ~/.ssh/id_personal -o IdentitiesOnly=yes"Personal project configuration is similar but uses:
- Personal email
- Personal SSH signing key
- Option not to force signing
- Uses a personal SSH key for authentication
hasconfig vs gitdir: Which to Use?
Both methods have their pros and cons:
| Feature | gitdir | hasconfig:remote.*.url |
|---|---|---|
| Decision Basis | File system path | Remote repository URL |
| Min Git Version | 2.13+ (2017) | 2.36+ (2022) |
| Evaluation Speed | Very fast | Slightly slower (requires scanning) |
| Flexibility | Requires organized directory structure | Location independent |
| Use Case | Projects with fixed directories | Projects scattered everywhere |
Recommended Strategy:
If you are accustomed to placing work and personal projects in different directories, using gitdir is the simplest:
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
[includeIf "gitdir:~/personal/"]
path = ~/.gitconfig-personalIf your projects are scattered everywhere, or you need to differentiate identities based on different Git hosting platforms, using hasconfig:remote.*.url is more flexible:
[includeIf "hasconfig:remote.*.url:https://gitlab.company.com/*/**"]
path = ~/.gitconfig-work
[includeIf "hasconfig:remote.*.url:https://github.com/personal/**"]
path = ~/.gitconfig-personalYou can also combine both for simplicity and flexibility.
Frequently Asked Questions
Question 1: Configuration not taking effect
Check the following:
- Is there a trailing slash in the path (
~/work/instead of~/work)? - Is the configuration file path correct (using absolute paths is safer)?
- Is your Git version new enough (
git --version)? - Is includeIf placed at the end of the configuration file?
Question 2: hasconfig pattern mismatch
# Check remote URL
git remote -v
# Check URL format
git config --get remote.origin.urlEnsure your pattern correctly matches the remote URL format.
Question 3: Multiple configuration conflicts
Git configuration priority from high to low:
- Command-line arguments (
git -c user.email=xxx@xxx.com) - Local repository configuration (
.git/config) - includeIf included configuration
- Global configuration (
~/.gitconfig) - System configuration (
/etc/gitconfig)
Later-read configurations will override earlier-read ones.