Git IncludeIf for Multiple Git Identities

When you maintain both work and personal projects, it is easy to use the wrong Git identity: committing to a company project with a personal email, or exposing a work email in an open-source project. Manually switching Git config is tedious and error-prone.

Git includeIf can automatically load different config files based on conditions, which makes it a good fit for managing multiple identities.

Why Do We Need includeIf?

In daily development, we often need to switch between different identities:

  • Work projects: Using a company email ([email protected]), company GPG signing key, company SSH key
  • Personal projects: Using a private email ([email protected]), personal GPG key, personal SSH key
  • Open-source contributions: Possibly another set of configurations

Without includeIf, you would need to:

  1. Remember to run git config user.email [email protected] every time you switch projects.
  2. Or manually set local configurations in each repository.
  3. Repeatedly check if the correct identity is being used before committing.

This manual approach is tedious and error-prone. Once you commit with the wrong identity and push to the remote repository, it can be 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/include

When 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

I. 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-personal

Notes:

  • 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.

II. Case-Insensitive Path Matching (gitdir/i)

Especially useful on Windows systems:

[includeIf "gitdir/i:C:/Work/"]
    path = C:/Users/username/.gitconfig-work

III. Based on Branch Name (onbranch)

Loads configuration based on the current branch:

[includeIf "onbranch:main"]
    path = ~/.gitconfig-main

IV. 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-work

Practical 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.gitconfig

Here, work:<name> and personal:<name> use Git’s URL alias feature.

Work Configuration ~/.gitconfig-work

[user]
    name = "Your Work Name"
    email = "[email protected]"
    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 = "[email protected]"
    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-personal

If 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-personal

You 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.url

Ensure your pattern correctly matches the remote URL format.

Question 3: Multiple configuration conflicts

Git configuration priority from high to low:

  1. Command-line arguments (git -c [email protected])
  2. Local repository configuration (.git/config)
  3. includeIf included configuration
  4. Global configuration (~/.gitconfig)
  5. System configuration (/etc/gitconfig)

Later-read configurations will override earlier-read ones.

References