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
includeIfline - 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.