Managing multiple git identities

author:ketz
readingTime:5 mins
date:09/Jun/2020

Split concerns, split personalities

It’s not uncommon these days for developers to have multiple identities with which to commit their code. Perhaps a set of credentials for their employer, another for their personal projects, and yet another if they are a student and need to connect to university-supplied servers.

Unfortunately git takes a fairly unstrict / unstructured approach to identity as it can be setup on a system with a single string. This means that services such as Bitbucket, Gitlab and Github may interpret even the slightest imprecision in configuration to represent a completely new identity. In addition to this, it can become very easy to add commits to a work repository using your personal email address if you aren’t careful.

Depending on your use case it might be important to ensure that your identities are kept separate from each other, particularly if you have email addresses that you don’t want to have exposed in public git repo commit histories. It’s for this reason that I use the setup that I’m about to describe. It’s pretty easy to setup and it works really well, let’s get started.

~~~

How does it work?

Without going too much into the technicalities of git, there are a few things you should know to help you understand the way this setup works.

Git has three levels of configuration:

However, these are only the config files that git will look for by default. It is actually possible for us to use the above configuration files to specify locations from which to source additional configuration conditionally using the includeIf directive, and that’s what we’re going to do here.

The setup

We need to setup a directory structure similar to this:

~
└── Source
  ├── home
  ├── uni
  └── work

The names don’t matter too much, however I’m pretty sure it is important that your source code lives in a directory underneath your home directory (as in: ~/$something).

Adding some configuration magic

Next we want to open up your existing global configuration file and add a few items to the bottom of it1.

...

[includeIf "gitdir:~/Source/home/"]
    path = ~/Source/home/.gitconfig

[includeIf "gitdir:~/Source/uni/"]
    path = ~/Source/uni/.gitconfig

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

Hopefully you can see where we’re going with this. We’ve added directives in the global configuration file so that when git is running underneath the specified directory2 (the “gitdir:~/…” one), it makes sure to also look for a configuration file that is available at the relevant path option.

So for example if I’m working in ~/Source/uni/my-great-project/, git will source configuration first from the global config file, and then by extension, it will merge the contents of the ~/Source/uni/.gitconfig file on top of that configuration.

These directory-based git configuration files work exactly the same as the standard global configuration file, with the same options and everything, except they will only apply to the subfolders underneath them.

~~~

An example

Here are some example config files to show the idea.

45
46
47
48
49
50
51
...

[includeIf "gitdir:~/Source/home/"]
    path = ~/Source/home/.gitconfig

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

1
2
3
[user]
  name = "Super Ketz"
  email = "supercool.email@ketz.internet"

1
2
3
4
[user]
  name = "Business Cat"
  email = "formal.cat@importantbusiness.com"
  signingkey = 0A46826A

Interested in signingkey?3

…and if we are playing around in a terminal window a bit, it might look like this (I’ve added spaces to help the visuals):

~ > pwd
/home/user

~ > git config --get user.name
Casual Cat

~ > cd Source/home

~/Source/home > git config --get user.name
Super Ketz

~/Source/home > cd ../work

~/Source/work > git config --get user.name
Business Cat

~/Source/work > █
~~~

Conclusion

I have successfully been using this approach for about two years now and it works very well for me. It might fall over if you are stuck working in a particular directory, for example developing something in go and are unable for some reason to use go modules.

Personally I am yet to encounter a situation like this and so this setup will remain in use for the forseeable future. Hopefully these concepts provide you a way to more easily manage git identities and stop different worlds blurring into each other.


  1. It should definitely be at the end of this file, otherwise anything specified underneath could “re-override” the configurations you’ve set within your directories 😱 ↩︎

  2. This is also recursive, meaning that it will apply to anything underneath the “gitdir:…" directory, and also any subdirectories underneath those too. ↩︎

  3. If you are interested by what signingkey is, you can find out more about it here. Essentially it is a way to configure GPG keys to cryptographically sign your commits, and therefore proving that it was almost certainly you that made a commit. ↩︎

sha256: 1d88ea136ff120e0f783a0edbd9deaa85bffd29f3c3e5b8a06c80d7c619d33c4 (898)
created: 2020-06-09 15:14:54 +1100 +1100