# 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 (`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:

1. Remember to run `git config user.email xxx@xxx.com` 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:

```ini
[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:

```ini
[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:

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

### III. Based on Branch Name (onbranch)

Loads configuration based on the current branch:

```ini
[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.

```ini
[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

```ini
[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

```ini
[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

```ini
[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:

```ini
[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:

```ini
[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**

```bash
# 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 user.email=xxx@xxx.com`)
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

- [Git Official Documentation - Conditional Includes](https://git-scm.com/docs/git-config#_conditional_includes)


---

> Author: Nite  
> URL: https://www.nite07.com/en/posts/git-includeif/  

