Git config with conditional includes per organization

tl;dr Organize your git config to seamlessly switch between private and work projects.

The problem

Most developers work on multiple projects - private open source contributions, freelance work, and one or more employers. Each organization often requires a specific git identity: your work email for company commits, your private email for open source, or maybe a mix of both when your company publishes open source projects as well.

When you set up git, you'll typically set a global username and email. You can override these per repository, but this quickly becomes tedious and error-prone.

The solution: a dotfile repo, an organized folder structure and conditional git includes.

Dotfiles

My git config lives in a dotfiles repository. A simple install script copies the config files to their expected locations. In Ubuntu this is ~/.config/git/.

When I set up a new machine - whether new hardware at work or joining a new employer - I clone my dotfiles repo and run the install script. Done.

A minimal install script in your dotfiles repo could look like this (with git config files in ./git/):

#!/bin/bash
cp -a ./git/* ~/.config/git/

Btw: The install script also sets up my favorite software, bash aliases, ssh configs etc. Whenever I change something on one machine, I commit the changes to the dotfiles repo and can easily propagate them to my other machines later, without having to remember what I changed where.

Folder structure

I organize all my Git projects in subfolders per organization:

~/git/
├── pixelbrackets/   # private projects
├── webit/           # work 1
├── acme/            # work 2
└── ...

First benefit: I always know where to find my projects and don't mix up work and private stuff. Second benefit: I can use these folder paths to trigger conditional git config includes.

Setting up conditional includes

The magic happens with conditional includes in the main git config.

In ~/.config/git/config I add conditional includes based on the directory:

[user]
    name = Dan Untenzu
    email = mail@pixelbrackets.de
[commit]
    template = ~/.config/git/commit-message-template

[includeIf "gitdir:~/git/webit/"]
    path = ~/.config/git/config-webit

[includeIf "gitdir:~/git/acme/"]
    path = ~/.config/git/config-acme

The default [user] section sets your private identity. The includeIf directives load additional config files only when working inside matching directories. The slash at the end of the gitdir path is important - it ensures that all subdirectories are matched as well.

Each included config file overrides the settings you need:

~/.config/git/config-acme

[user]
    name = Dan Untenzu
    email = dan@acme.com

[commit]
    template = ~/.config/git/commit-message-template-acme

You can override anything - username, email, commit message templates, signing keys, or even aliases specific to an organization.

Verify it works

Check which identity is active in any repository:

cd ~/git/pixelbrackets/some-project
git config user.email
# mail@pixelbrackets.de

cd ~/git/acme/company-project
git config user.email
# dan@acme.com

Benefits

  • Portable setup: Clone dotfiles, run install script, done
  • Automatic identity switching: No manual config per repository
  • Easy onboarding: New job? Add one config file and one includeIf line
  • Version controlled: Track changes to your git config over time
  • Shareable: Publish your aliases while keeping work configs private

Combined with my git aliases, this setup makes working across multiple organizations seamless.

Update: This approach also solves another common problem: using separate SSH keys per organization.

When your work requires separate GitHub or GitLab accounts, you'll run into a limitation: GitLab and GitHub don't allow the same SSH key to be registered on multiple accounts.

The typical workaround are SSH host aliases - configuring github.com-work in your SSH config and using that when cloning. But you'll probably forget this every time you clone a repo. I do.

So I found a better solution: use git's core.sshCommand to overwrite SSH settings with conditional includes.

Setting up per-directory SSH keys

First we generate separate SSH keys for private and work use. Then we set the default key in the main git config.

[core]
    sshCommand = ssh -i ~/.ssh/id_rsa -o IdentitiesOnly=yes

The IdentitiesOnly=yes flag ensures only the specified key is offered to the server, preventing SSH from trying other loaded keys.

In the organization-specific config ~/.config/git/config-acme, override the SSH command again.

[core]
    sshCommand = ssh -i ~/.ssh/id_rsa_work -o IdentitiesOnly=yes

Now repositories in ~/git/acme/ automatically use the work SSH key, and therefore the work GitHub/GitLab account, while all other repos use your personal key and account.

⌛ Warning! This post is old. The information may be outdated.

No comments on this notepad. If you would like to add something, then don't hesitate to contact me via E-Mail, Mastodon or other social profiles.