Select The Email For Git Commits Based On The Current Directory

My new job requires that commits in our repos are signed with our work emails. Setting the global email address is no problem:

> git config --global user.email "my.work@email.com"

For no important reason, other than that I believe in the sanctity and purity of a git log (sorry, Pavlos), I decided that I want commits in my personal repos to be signed with my personal email.

Heads up: this isn't an article about setting up authentication for two different users — that is pretty well described in this article about multiple SSH keys. This article is about using two different email addresses to sign commits.

You could use repo-level .gitconfigs

The previously linked article mentions one way to use my personal email on my personal repos — but it requires setting the local git config on each repo. This is similar to how we set it above globally:

> git config user.email "my.personal@email.com"

We aren't specifying --global here, so it's applying the configuration change to the current repo only.

This is probably a fine way to solve the problem, but I don't like the idea of having to remember to do this for every personal repo I clone. I see a very likely future where I clone a repo, make a handful of commits and push them up, then realize they were signed with my work email. 😝

Folder-level .gitconfigs don't exist

Structurally, I keep my projects organized in a single folder that clarifies the owner: ~/dev/personal/, vs ~/dev/camunda/.

I'd love to be able to create one .gitconfig in the ~/dev/personal/ folder, and have it apply to all its child repos. That's not supported, unfortunately. I guess this makes sense, as it might be asking a lot for git to crawl up the tree to find all configuration files.

Conditional git includes FTW

We can use conditional git includes to solve the problem! (h/t this StackOverflow answer)

To use a conditional git include, you specify a condition and a path to a file. If the condition is met, the file is expanded and its contents are included in your configuration.

The condition could be something like onbranch, to assess which branch you're currently on, or hasconfig:remote.*.url to look for a specific remote URL. In our case, we'll use the gitdir condition to assess the repo's working directory.

We'll set this up so that the global .gitconfig contains my work email. If a gitdir condition is met based on the repo's directory, a partial .gitconfig will override the email with my personal one.

The final solution

My global .gitconfig contains my default email address, and the conditional include:

[user]
  name = Steven Hicks
  email = my.work@email.com
[includeIf "gitdir:~/dev/personal/"]
  path = .gitconfig-personal

For any repos that are inside that ~/dev/personal/ folder, the .gitconfig-personal file will be applied. The .gitconfig-personal file contains only the properties I want to override:

[user]
  email = my.personal@email.com

Proof

You can pass a flag to git config to tell it to list out the current configuration: git config -l.

When I'm in a work directory, this emits my default email address:

❯ git config -l

user.name=Steven Hicks
user.email=my.work@email.com
includeif.gitdir:~/dev/personal/.path=.gitconfig-personal

Note that the includeif shows up here, but the condition was not met, so it doesn't bring over the contents of the conditional file.

Most importantly, when I'm working in a personal repo, I see my personal email address:

❯ git config -l

user.name=Steven Hicks
user.email=my.work@email.com
includeif.gitdir:~/dev/personal/.path=.gitconfig-personal
user.email=my.personal@email.com

It actually includes both email addresses...but the last one wins, and git uses my personal email address to sign the commits.


Is this the only way to solve this problem? Likely not. If you know of another way, let me know!