As an independent software engineer I often find myself working with clients who use different Git providers or who might require me to have a client-specific Git configuration. For a long time this resulted in me having a complex and difficult to maintain Git configuration, and some really hacky shell aliases which did some on the fly Git reconfiguration depending on which repository I was in… Not nice!

But then I discovered what seems to be a little known piece of Git configuration. which goes by the name of hasconfig:remote.

This configuration, which exists in Git vertion 2.36 onwards, allows Git to conditionally include configuration based on a pattern match, which is applied to the remote URL of each repository. The pattern matching is flexible enough that it can be used to identify different Git providers e.g. Gitlab vs GitHub or different path segments (which often map to repositories owned by a particular client).

User Story

Let’s start with a user story (albeit a slightly contrived one where I’m the user!):

As a software engineer working with multiple clients who use Git
When I work with a Git repository belonging to a given client 
I want Git to automatically configure itself with the correct settings for that client
So that I can keep my Git configuration simple
And so that I can maintain separate Git configuration for each client

Worked example

Here’s a worked example:

Let’s say I’m working with 2 clients right now:

  • Funky Corp
  • Groovy Corp

Both of the above clients have their own GitHub organisation, where they keep their source code:

  • Funky Corp: github.com/funkycorp
  • Groovy Corp: github.com/groovycorp

Each organisation requires me to:

  1. Use a GitHub account which is specific to their organisation.
  2. Using an email address which is specific to their organisation.
  3. Use a GPG signing key which is specific to their organisation.

Using the new syntax I can configure my .gitconfig file to conditionally include the relevant config for each of the 2 clients mentioned above:

# Start with defaults.
[core]
    autocrlf = input
[init]
    defaultBranch = main
	
# Here are the conditional, organsation specific includes.
[includeIf "hasconfig:remote.*.url:git@github.com:funkycorp/**"]
    path = "~/.gitconfig.funkycorp.inc"
[includeIf "hasconfig:remote.*.url:git@github.com:groovycorp/**"]
    path = "~/.gitconfig.groovycorp.inc"

I would then specify the appropriate settings for each client in the respective include file:

~/.gitconfig.funkycorp.inc:

[user]
    email = eg1@funkycorp.org
    name = egfunk1
    signingkey = <my funky corp gpg signing key>
[commit]
    gpgsign = true

~/.gitconfig.groovycorp.inc:

[user]
    email = eg1@groovycorp.org
    name = eggroove1
    signingkey = <my groovy corp gpg signing key>
[commit]
    gpgsign = true

Then, when I clone a repository from one client we can see that Git automatically applies the correct configuration:

gh repo clone funkycorp/test-repo
git config --show-origin --show-scope --get user.name      
global	file:/home/<username>/.gitconfig.funkycorp.inc	egfunk1

All we’re doing here is matching the repository remote on its URL, so it should be perfectly possible to extend this out to other Git hosting providers e.g. BitBucket, GitLab etc.

Note: As per this note This feature is only available in Git 2.36 and later versions, earlier versions will silently ignore the additional configuration.

Let me know in the comments below if this helps you simplify your Git configuration.

Until next time!

Edd