The Git Config Settings I Actually Use
A few years back, I set up a two-repository system for this site: one repo for content, another for the theme (living as a submodule). It’s a clean architecture in theory, but in practice, managing two repos means you’re constantly juggling branch updates, resolving submodule pointer conflicts, and pushing to two remotes in sequence. I started carrying around a .gitconfig file between machines, tweaking it bit by bit as I discovered settings that eliminated friction.
This isn’t a guide to every git option, that would be a book. Instead, it’s a personal tour through the settings I’ve actually integrated into my workflow, why they matter, and what changed once each one was on.
The Setup Glue: push.autoSetupRemote and pull.rebase
These two live together because they’re about the boundaries of your branches: pushing them up and pulling them back down.
push.autoSetupRemote
The old frustration: cut a new branch locally, write code, run git push, and get:
|
|
It’s boilerplate ceremony every time you push a new branch. The fix:
|
|
Now git push on a new branch just works. It infers the tracking branch automatically. The first time I used this with Hugo content branches, cutting content/new-article on Monday and pushing immediately, I realized I’d eliminated maybe fifty typos a year of --set-upstream.
pull.rebase
Linear history matters more on a single-author site. Without pull.rebase = true, pulling changes creates merge commits like “Merge branch ‘main’ of origin/main” even when you’re just syncing. These commits don’t represent work; they’re noise. They clutter git log, make bisecting slower, and add confusion to the graph.
|
|
With this on, pulling rebases your local work on top of the remote tip. When you’re managing a Hugo site with a theme submodule, this is especially helpful: submodule pointer updates stay tidy in the log instead of hiding inside merge commits.
Identity and Trust: commit.gpgsign
GPG signing commits isn’t about compliance or passing audits. It’s about provenance. Every commit on my repos carries my cryptographic signature, proof that it came from me and hasn’t been tampered with.
|
|
The first time you set this up, know that gpg-agent needs to be running and your key needs to be imported locally. Once both are in place, every commit is signed automatically. If you want to dive deeper into GPG keys, I wrote about managing passwords with password-store, which covers key setup.
Reducing Friction: help.autocorrect, fetch.prune, and fetch.prunetags
Three small settings that save daily typing and mental overhead.
help.autocorrect
Typos happen. I often type git statsu instead of git status, or git comit instead of git commit. The old behavior is an error message and a suggested fix. With:
|
|
Git autocorrects and runs the command after a 1-second countdown:
|
|
The 10 here means 1 second (git measures in tenths). It’s long enough to notice and interrupt if the correction is wrong, but short enough not to interrupt workflow.
fetch.prune and fetch.prunetags
When teammates delete branches on the remote, stale refs accumulate in your local repository. These settings clean them up:
|
|
Now git fetch silently removes local branches that no longer exist upstream, and does the same for tags. For a Hugo theme repo, old release tags get cleaned up on the server, and prunetags means they don’t linger in your local git tag output.
When Conflicts Happen: merge.conflictstyle and rerere
Two settings that make merge conflicts less painful.
merge.conflictstyle = zdiff3
Conflict markers normally show you two sides:
|
|
You see what you wrote and what they wrote, but not what you both started from. The zdiff3 conflict style shows the ancestor:
|
|
The ||||||| base section is what both sides changed from. Now you can see the full story: you changed this line to X, they changed it to Y, and the original was Z. Intent becomes obvious.
|
|
rerere.enabled and rerere.autoupdate
rerere stands for “reuse recorded resolution.” When you resolve a conflict manually, git remembers the resolution. The next time you hit the same conflict:
|
|
Git resolves it automatically. This is invaluable when rebasing a content branch over a main that includes a submodule pointer update. The first time there’s a conflict in the submodule reference, you resolve it. On a second branch with the same conflict, rerere handles it silently, and autoupdate stages the resolution so you don’t have to git add it manually.
Looking Around: Branch Display, Logs, and Diffs
Four settings that make reading your repository history faster.
branch.sort and column.ui
|
|
By default, git branch lists branches alphabetically. Useless past ten branches. The -committerdate sort shows newest first, so the branch you’re probably about to switch to is at the top.
column.ui = auto displays branches in multiple columns when your terminal is wide enough, cutting down on scrolling through a long list.
log.abbrevCommit and log.follow
|
|
abbrevCommit shows short SHAs (7 chars) instead of full 40-character hashes. Cleaner logs, faster to read.
follow tracks files through renames. When you run git log -- path/to/article.md and that file was once named old-article.md, log doesn’t break, it follows the file through the rename and shows the full history.
diff.mnemonicPrefix, diff.renames, and diff.wordRegex
|
|
mnemonicPrefix changes the diff headers from a/ and b/ to more descriptive labels like i/ (index), w/ (working tree), o/ (object), c/ (commit). More information at a glance.
renames = true detects file renames and shows them as file.old => file.new instead of a delete and a create. Cleaner diffs.
wordRegex defines what counts as a “word” in word-level diffs (git diff --word-diff). The pattern [^[:space:]] treats any non-whitespace as a word, which means punctuation gets its own boundaries, useful for prose-heavy files like Markdown articles.
Shorthand That Earns Its Place: Aliases
I keep aliases minimal on purpose. Aliases that hide what git is doing are noise; these two are worth the keystroke savings.
lg: Pretty-print log with graph
|
|
Running git lg shows a colored graph with commit hashes, dates, messages, authors, and branch pointers:
|
|
Much better than plain git log.
sw: Switch shorthand
|
|
git sw main is faster than git switch main, and git sw -c feature/new creates and switches in one command.
A Typical Day
Here’s how these settings work together in practice.
Morning: sync with the repo. git fetch fires silently in the background, fetch.prune and prunetags cleaning up any deleted branches and old tags without you thinking about it.
I’m starting the week’s Hugo article. Cut a new content branch:
|
|
No typing --set-upstream later. push.autoSetupRemote has me covered.
Write, commit. The commit is GPG-signed automatically. No extra steps.
|
|
Push when done:
|
|
No upstream error. Just works.
Later, the main branch gets a theme submodule update. I rebase my work on top:
|
|
There’s a conflict in the submodule pointer, the theme repo moved forward. merge.conflictstyle = zdiff3 shows me exactly what changed. I resolve it once.
Later, a second branch has the same submodule conflict. rerere remembers my resolution and applies it automatically with rerere.autoupdate. No re-resolving.
Before merging back to main, check the graph:
|
|
Pretty output shows the timeline clearly.
Merge to main:
|
|
If there’s a conflict here (unlikely given we rebased), zdiff3 shows the ancestor context.
Done. All the settings worked together transparently.
The Full Config
Here’s the complete block as it sits in my ~/.gitconfig:
|
|
Copy what you need. Leave what doesn’t fit your workflow.
A Config That Evolves
This isn’t the “correct” git configuration, it’s the one that fits how I work. I’ve been refining it for years, and it’ll keep evolving as I hit new friction points and discover new settings. The point isn’t to follow mine exactly, but to think about what’s slowing you down and look for the git setting that fixes it.
If you use any of these settings, or if you’ve found others that changed your workflow, let me know in the comments. I’m always curious how other people configure their tools.