Using multiple GPG keys for different git repositories

Posted on August 23, 2019

In a previous article, I generated a GPG key to sign commits in Git. I've started in a new company and generated a new key to separate my work profile from my personal profile. In this article, I'm going to explain how to split your git configuration and then conditionally include custom configuration based on the current directory you're currently in.

For the rest of this article, I'll assume you have just generated a new key and has the long id ready. You can check my previous article to see how to generate a key and retrieve the long key.

Splitting your git configuration

Git has a lot of options and normally you put them in a .gitconfig file in your $HOME folder. What many people don't know is that you are able to include another .gitconfig file and — even better — we can even conditionally include them so you don't need to add some very specific stuff to your versioned .gitconfig file.

The simplest way to do this is using a static include, i.e., a file that will always be included if it exists. If the specified file does not exists, git will fail silently.

Just so you understand how it works, we will create a .gitconfig-local file in your $HOME folder and we'll include it. Run the following command:

git config --get meta.isLocalConfig

Output of the previous command: nothing

You should see no output. Now, let's add that configuration to the local file and see if git is able to read it:

git config -f ~/.gitconfig-local meta.isLocalConfig true

Now we run the command again and… still no output. What's going on?

Well, we need to tell git to look for this file. The name .gitconfig-local means nothing, it's just an arbitrary name. Let's tell git that we wish to include this configuration file

git config --global include.path "~/.gitconfig-local"

And, finally, run again:

git config --get meta.isLocalConfig

Finally, the config works!

Remember, the configuration in the included file will *override** any configuration from the global .gitconfig file.

Configuring Git to use the second key

So, assuming you have your long key id ready, let's create a file for your work configuration and add your work email:

git config -f ~/.gitconfig-work user.email <your.work@email.com>

After that, make sure you have the long id for your work GPG key and configure git to use this key:

git config -f ~/.gitconfig-work user.signingkey `A5A675575744B557`

Your ~/.gitconfig-work file should look something like the file below:

[user]
    name = Filipe Kiss
    email = filipe.kiss@work.com
	signingkey = A5A675575744B557

Include this file only for work repositories

Now that we have a configuration file for work, we need to tell git when to use this file. Instead of using a include directive, we're going to use the includeIf option. For the sake of this example, let's assume you have the following structure:

$HOME
├── personal
│   └── other-repository
└── work
    └── repository

As you can see, there's a work folder where I'd like to use my work signing key instead of my personal one. Let's tell git to include the ~/.gitconfig-work file when we're in $HOME/work/repository:

git config --global "includeIf.gitdir:~/work/.path" "~/.gitconfig-work"

Now, if you open your .gitconfig, at the very end, you should find something like this:

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

What this means is "if you're in a git folder that's under ~/work, include the ~/.gitconfig-work file". You can have multiple includeIf statements for different setups, like work, open source or whatever.

To ensure everything works, let's add a key that's only available on .gitconfig-work:

git config -f ~/.gitconfig-work core.isWork true

No go to any repository that's not under $HOME/work and run the following:

git config --get core.isWork || echo false

Terminal showing "false" as output

The output should be false. No go to a git repository under the $HOME/work and run the same command and the output should be true

Terminal showing "true" as output

And that's how I have different git configurations depending on what I'm working on and which I don't ever have to remember to swap one for the other: Git does itself.