Building a Robust .gitconfig

Getting started with Git is easy (ha!), but once you’ve mastered the basics, it’s natural
for developers to start thinking about customising their git process.
Most Git settings live in the .gitconfig file.
In this blog post, I’ll discuss what you should consider setting in your config file to make a more efficient development environment.
Adding and Removing Variables
You can edit your global .gitconfig using any standard editor.
It should live in your home directory. If you have difficulty finding it, try
git config --edit --global
Standard Settings
These settings are probably(?) suitable for everyone. First, your name and email address you use when committing
[user]
name = Colin Gillespie
email = colin@jumpingrivers.com
At Jumping Rivers, we enforce that the email address matches a particular pattern, (@jumpingrivers.com), when committing to the corporate repo. This standardises our internal commit history. However, most people require a couple of identities - see the end of this post for details.
[core]
excludesfile = ~/.gitignore
editor = emacs
The excludesfile setting points to a global .gitignore file and allows you to exclude files regardless of the project. My global ignore file is fairly light.
It contents file names, such as .Rhistory, ^tmp\\.*, and \.vscode, that I never want to commit.
The editor setting determines which text editor Git opens for commit messages and interactive operations.
I still cling to Emacs, but most people probably prefer other options are vim, nano, or code --wait for Visual Studio Code.
Enabling colour output makes Git’s terminal output more readable. Different elements (additions, deletions, branch names, etc.) are highlighted in different colours, making it easier to scan and understand what’s happening at a glance.
[color]
ui = 1
Almost all of the repositories I deal with use main for their default branch.
This can be set via
[init]
defaultBranch = main
Setting pull.rebase = true makes git pull rebase your local commits on top of the upstream changes rather than creating merge commits, resulting in a cleaner history - but can be very annoying!
[pull]
rebase = true
The autoSetupRemote = true setting automatically sets up remote tracking when you push a new branch, eliminating the need for git push -u origin branch-name drama.
[push]
default = simple # This is the default in modern Git versions
autoSetupRemote = true
Branch Management
This setting changes how Git sorts branches when you run commands like git branch.
By default, Git sorts branches alphabetically - but alphabetically is rarely useful for me.
[branch]
sort = -committerdate
Useful Aliases
You can also set git aliases
[alias]
root = rev-parse --show-toplevel
The root alias provides quick access to the repository’s root directory - useful when you’re deep in a nested folder structure and need to reference files relative to the project root.
You can use it simply with git root, which will output the absolute path to your repository’s top-level directory.
I’ve also created a zsh alias - gcd that does this, as I found it really handy.
Security Settings
This section tackles the following problems
- We use ssh for checking out repositories
- The ssh key is stored securely and is Password protected, i.e. encrypted
- Git commits are signed
Over the years, I’ve tried a few different methods, but as we (Jumping RIvers), use 1Password to manage credentials, I want to use the same system.
The ssh key is stored in 1Password.
[commit]
gpgsign = true
[user]
signingkey = ssh-ed25519 ABCD
[gpg]
format = ssh
[gpg "ssh"]
program = "/opt/1Password/op-ssh-sign"
Commit signing verifies that commits genuinely come from you, which is increasingly important in professional environments.
This configuration uses SSH keys rather than traditional GPG keys (note the format = ssh setting).
I’ve used GPG keys in the past, and they can be tricky.
The configuration integrates with 1Password’s SSH agent, allowing seamless signing without managing separate GPG keys. When you make a commit, 1Password handles the signing process automatically. It also means, that you don’t have to constantly enter your password to decrypt your ssh key.
Another feature of this set-up, is that it’s much easier to have multiple ssh keys, rather than “one key to rule them all”.
Pack Optimisation
This setting controls how aggressively Git compresses repository data. A depth of 20 balances storage efficiency against the computational cost of packing and unpacking objects. Lower values mean faster operations but larger repositories; higher values save space but slow down operations slightly.
[pack]
depth = 20
To be honest, this has been “stolen” from a long forgotten blog post/tweet/StackOverflow question.
Conditional Includes for Work/Personal Separation
This, in my humble opinion, is an elegant solution for managing different Git identities.
When working in repositories under /home/colin/jumpingrivers/, Git loads additional configuration from .gitconfig-work.
[includeIf "gitdir:/home/colin/jumpingrivers/"]
path = .gitconfig-work
The .gitconfig-work file contains any new or updated variables, i.e.
[user]
email = colin@jumpingrivers.com
This is perfect for using different email addresses on different projects.
Putting It All Together
A well-configured .gitconfig file transforms Git from a tool you fight with into one that works seamlessly with your workflow.
Avoid copying and pasting configuration options you don’t understand.
Instead, consider each change turn, and add to your .gitconfig file.
Remember, you can view your current configuration at any time with git config --list and edit it with git config --global --edit.
