Configuring Git¶
Git is deeply configurable. Every aspect of its behavior - from how it displays output to how it handles line endings - can be tuned through configuration. Understanding the configuration system lets you build a Git setup that matches your workflow, your editor, and your team's conventions.
Configuration Levels¶
Git reads configuration from four levels, each overriding the previous:
| Level | Flag | Location | Scope |
|---|---|---|---|
| System | --system |
/etc/gitconfig |
Every user on the machine |
| Global | --global |
~/.gitconfig or ~/.config/git/config |
Your user account |
| Local | --local |
.git/config in the repo |
One repository |
| Worktree | --worktree |
.git/config.worktree |
One worktree (Git 2.20+) |
A setting at a more specific level overrides the same setting at a broader level. Local overrides global, global overrides system.
# See all settings and where they come from
git config --list --show-origin
# See just global settings
git config --global --list
# See just local (repo) settings
git config --local --list
Reading and Writing Configuration¶
Setting Values¶
# Set a value
git config --global user.name "Jane Developer"
# Set with a specific scope
git config --local core.autocrlf input
# Set a boolean
git config --global color.ui true
Reading Values¶
# Get a specific value
git config user.name
# Get with scope
git config --global user.email
# Get showing the origin
git config --show-origin user.name
Removing and Editing¶
# Remove a specific key
git config --global --unset core.editor
# Remove a section
git config --global --remove-section alias
# Open config in editor
git config --global --edit
Aliases¶
Aliases let you create shortcuts for Git commands you use frequently. They range from simple abbreviations to complex shell commands.
Simple Aliases¶
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.sw switch
Now git st runs git status, git co main runs git checkout main, and so on.
Compound Aliases¶
# Compact log with graph
git config --global alias.lg "log --oneline --graph --all --decorate"
# Unstage files
git config --global alias.unstage "reset HEAD --"
# Show last commit
git config --global alias.last "log -1 HEAD --stat"
# Diff of staged changes
git config --global alias.staged "diff --staged"
# List branches sorted by last commit date
git config --global alias.recent "branch --sort=-committerdate --format='%(committerdate:relative)%09%(refname:short)'"
Shell Command Aliases¶
Prefix with ! to run arbitrary shell commands:
# Delete all merged branches except main/master
git config --global alias.cleanup '!git branch --merged | grep -v "main\|master\|\*" | xargs -r git branch -d'
# Show all aliases
git config --global alias.aliases '!git config --get-regexp ^alias\. | sed s/alias\.//'
# Open the repo in the browser (GitHub)
git config --global alias.browse '!open $(git remote get-url origin | sed "s/git@/https:\/\//" | sed "s/\.git$//" | sed "s/:/\//")'
Custom Diff and Merge Tools¶
Git's built-in diff and merge output works in the terminal, but graphical tools can be easier for complex diffs and multi-file merge conflicts.
Configuring a Diff Tool¶
# Use vimdiff
git config --global diff.tool vimdiff
# Use VS Code
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
# Use meld (Linux)
git config --global diff.tool meld
Run the visual diff:
git difftool # Working dir vs staging
git difftool --staged # Staging vs HEAD
git difftool main feature/auth # Between branches
Configuring a Merge Tool¶
# Use vimdiff
git config --global merge.tool vimdiff
# Use VS Code
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'
# Show the base version in conflicts (highly recommended)
git config --global merge.conflictstyle diff3
Run the merge tool during a conflict:
git merge feature/branch # Conflict occurs
git mergetool # Opens each conflicted file in the configured tool
diff3 conflict style
merge.conflictstyle = diff3 adds a third section to conflict markers showing the base version (what the code looked like before either change). This makes it much easier to understand the intent of both changes. Set it globally - you'll wonder how you ever resolved conflicts without it.
Conditional Includes¶
If you use Git for both work and personal projects, you need different identities (name, email, signing key) for each. Conditional includes (Git 2.13+) let you load different configuration files based on the repository's location:
# ~/.gitconfig
[user]
name = Jane Developer
email = jane@personal.com
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
[includeIf "gitdir:~/opensource/"]
path = ~/.gitconfig-opensource
# ~/.gitconfig-work
[user]
email = jane.developer@company.com
signingkey = ~/.ssh/work_ed25519.pub
[commit]
gpgsign = true
Any repository under ~/work/ automatically uses the work email and signing key. Repositories elsewhere use the personal defaults.
The gitdir: condition matches the .git directory location. Other conditions:
| Condition | Matches |
|---|---|
gitdir:~/work/ |
Repos under ~/work/ |
gitdir/i:~/Work/ |
Case-insensitive match (useful on macOS) |
onbranch:main |
When the main branch is checked out |
hasconfig:remote.*.url:*github.com* |
Repos with a GitHub remote (Git 2.36+) |
Core Settings¶
The core.* namespace contains Git's most fundamental behavior settings.
Line Endings¶
Line ending handling is critical for cross-platform teams. Windows uses CRLF (\r\n), Linux and macOS use LF (\n).
# On Linux/macOS: convert CRLF to LF on commit, no conversion on checkout
git config --global core.autocrlf input
# On Windows: convert LF to CRLF on checkout, CRLF to LF on commit
git config --global core.autocrlf true
# No conversion (if your team standardizes on LF and uses .gitattributes)
git config --global core.autocrlf false
Use .gitattributes for line endings
core.autocrlf is a per-user setting - it only works if everyone configures it. .gitattributes is committed to the repository and enforces line ending rules for the whole team. See the .gitattributes section below.
Other Core Settings¶
# Set your editor (for commit messages, rebase, etc.)
git config --global core.editor "vim"
# git config --global core.editor "code --wait"
# git config --global core.editor "nano"
# Set the pager (for log, diff, etc.)
git config --global core.pager "less -FRX"
# Detect whitespace problems
git config --global core.whitespace trailing-space,space-before-tab
# Improve performance on large repos with filesystem monitor
git config --global core.fsmonitor true
.gitattributes¶
While .gitconfig controls your personal Git behavior, .gitattributes is committed to the repository and controls per-file behavior for the whole team: line endings, diff drivers, merge strategies, and LFS tracking.
Line Endings¶
# .gitattributes - normalize line endings
# Default: auto-detect
* text=auto
# Force LF for source files
*.py text eol=lf
*.js text eol=lf
*.css text eol=lf
*.html text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.json text eol=lf
# Force CRLF for Windows-specific files
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# Binary files (no conversion, no diff)
*.png binary
*.jpg binary
*.gif binary
*.ico binary
*.zip binary
*.pdf binary
Custom Diff Drivers¶
These tell Git to use language-aware diff heuristics - better function/class detection in diff headers.
Linguist Overrides¶
# Exclude from GitHub language statistics
docs/* linguist-documentation
vendor/* linguist-vendored
*.min.js linguist-generated
Environment Variables¶
Git reads several environment variables that override configuration:
| Variable | Overrides | Use case |
|---|---|---|
GIT_AUTHOR_NAME |
user.name |
Set author for the current command |
GIT_AUTHOR_EMAIL |
user.email |
Set author email for the current command |
GIT_COMMITTER_NAME |
user.name |
Set committer identity |
GIT_COMMITTER_EMAIL |
user.email |
Set committer email |
GIT_DIR |
default .git |
Path to the .git directory |
GIT_WORK_TREE |
default parent of .git |
Path to the working tree |
GIT_EDITOR |
core.editor |
Editor for commit messages |
GIT_PAGER |
core.pager |
Pager for output |
GIT_SSH_COMMAND |
core.sshCommand |
Custom SSH command |
# One-off commit with a different author
GIT_AUTHOR_NAME="Pair Partner" GIT_AUTHOR_EMAIL="pair@example.com" git commit -m "Paired on auth fix"
# Use a different SSH key for one command
GIT_SSH_COMMAND="ssh -i ~/.ssh/deploy_key" git push
.mailmap: Author Normalization¶
Over time, contributors may use different names or emails across commits. .mailmap normalizes these for git log and git shortlog:
# .mailmap
Jane Developer <jane@current.com> <jane.dev@oldcompany.com>
Jane Developer <jane@current.com> <jdev@personal.com>
Bob Smith <bob@company.com> Bobby <bobby@typo.com>
Now git shortlog -sne shows unified author counts instead of splitting the same person across multiple entries.
Further Reading¶
- Pro Git - Chapter 8.1: Customizing Git Configuration - comprehensive coverage of configuration options
- Official git-config documentation - complete reference for all settings
- Official gitattributes documentation - line endings, diff drivers, merge strategies, LFS
- Official gitignore documentation - pattern syntax and precedence
Previous: Stashing and the Worktree | Next: The Object Model | Back to Index