The git logo with the title of the article superimposed next to it.

Small secrets, big wins.

Do you track your git config across machines or keep it in sync with your dotfiles? Is it full of settings that you want to share between all your different contexts? Are there certain things that you want to change depending on what the context is? Well, I've got news for you!

tl;dr:

If you want to use an additional config file for all subdirectories below a certain path, use the includeIf functionality that was introduced in git 2.13.0.

[includeIf "gitdir:<path to top directory to use the config in>/"]
path = <path to extra config>

That's all you need to get going, but if you want to know more about how this works and some caveats you might to be aware of, keep reading.

include and includeIf

First off, I'd be remiss not to direct you to the official documentation for this feature, which can be found here. However, there's loads more info there than you might need (and want), so let's extract the important bits.

The include and includeIf sections work the same, except the includeIf has a condition that must be satisfied. They let you insert configuration from another file into your main one.

In my case, this meant that I could automatically change my email whenever the git directory was a subdirectory of ~/projects/work, allowing me a simple and efficient way to always use my work email for work, without changing my global git config or branching off from my main dotfiles repo.

Here's the relevant extract from my config:

[includeIf "gitdir:~/projects/work/"]
path = ~/projects/work/.gitconfig

I keep a separate config file in the ~/projects/work directory that overrides my email.

This would also be useful if your team has specific rules about whitespace, merge strategies, comment characters, etc. that you want to enforce.

Things that might trip you up

Syntax
Note the trailing slash after the directory path in the includeIf line. This makes it so that it will match all subdirectories of the specified directory. As explained by the docs:
If the pattern ends with ~/~, ~**~ will be automatically added. For example, the pattern ~foo/~ becomes ~foo/**~. In other words, it matches "foo" and everything inside, recursively.

This also means that if there is no trailing slash, it'll match only that specific directory.

File insertion
Here's another quote from the documentation:
The contents of the included file are *inserted immediately, as if they had been found at the location of the include directive*. If the value of the variable is a relative path, the path is considered to be relative to the configuration file in which the include directive was found.

So you'll probably want to put the includes at the bottom of your files to make sure the included config isn't overridden later on in the source file.


I hope that cleared some things up for you and that you found it useful; I know I did. If you want more in-depth information, see the documentation.



Thomas Heartman is a developer, writer, speaker, and one of those odd people who enjoy lifting heavy things and putting them back down again. Preferably with others. Doing his best to gain and share as much knowledge as possible.