Git colour config — color.ui, slots, pager, --color=always
Git emits ANSI / VT escape codes for diff, status, log, branch, grep, and the interactive picker — each subcommand has its own switch, every output element has a named slot you can recolour, and the default less pager strips SGR unless you tell it not to. Seven copy-paste snippets below cover the full configuration map, from the global color.ui switch down to the canonical LESS=FRX pager flags and the git log --color=always | less -R pipe recipe.
Configuration snippets
color.ui — the global on/off switch (default since git 1.8.4)
Since git 1.8.4 (August 2013) the default for color.ui is auto — git emits SGR when stdout is a TTY and strips it when piped. Older builds defaulted to false; legacy .gitconfig files often pin false for no reason. The valid values are auto (TTY-only), always / true (always emit — useful when piping into a renderer like less -R), and never / false (never emit). color.ui is the only switch that affects all subcommands at once; per-command keys (color.diff etc.) override it.
# Inspect current value (auto = sane default).
git config --get color.ui
# The sane default — emit colour on TTY, strip on pipe:
git config --global color.ui auto
# Force colour through pipes (for piping into less -R, see snippet 6):
git config --global color.ui always
# Disable globally (e.g. dumb terminal, log scraping, or accessibility):
git config --global color.ui never
# or honour the universal env var (git respects NO_COLOR since 2.21):
NO_COLOR=1 git diffcolor.diff / color.status / color.branch / color.grep / color.interactive — per-command override
Every subcommand that emits coloured output has its own color.<command> key that overrides color.ui for that command. Same values: auto, always / true, never / false. Use these when you want colour everywhere except one command (e.g. you pipe git status into a script but want git diff coloured), or when honouring a corporate .gitconfig that disables global colour but you want it back for diff.
# Per-command keys, all default to value of color.ui:
git config --global color.diff auto
git config --global color.status auto
git config --global color.branch auto
git config --global color.grep auto
git config --global color.interactive auto
git config --global color.decorate auto # git log --decorate
git config --global color.pager true # respect color when paged
git config --global color.advice auto # hint messages
git config --global color.push auto # since git 2.41
git config --global color.remote auto # since git 2.21
# Example: force colour for diff specifically, leave everything else auto:
git config --global color.diff alwayscolor.<cmd>.<slot> — the named-slot palette system
Each subcommand has named "slots" — individual elements of its output you can recolour. The value syntax is <fg> [<bg>] [<attr>...], where colours are named (red / green / yellow / blue / magenta / cyan / white), numeric 256-palette (231), or 24-bit hex ("#ff8000", git 2.26+). Attributes: bold, dim, italic, underline, blink, reverse, strike. Prefix any of fg/bg/attr with no- to clear an inherited value. Slots not listed below fall back to git's built-in defaults.
# git diff slots — most commonly retuned for readability:
git config --global color.diff.meta "yellow bold"
git config --global color.diff.frag "magenta bold"
git config --global color.diff.func "cyan"
git config --global color.diff.context "white"
git config --global color.diff.old "red bold"
git config --global color.diff.new "green bold"
git config --global color.diff.whitespace "red reverse"
git config --global color.diff.commit "yellow"
# git status slots:
git config --global color.status.header "white"
git config --global color.status.added "green"
git config --global color.status.updated "green"
git config --global color.status.changed "yellow"
git config --global color.status.untracked "red"
git config --global color.status.branch "cyan bold"
git config --global color.status.nobranch "red reverse"
# git branch slots:
git config --global color.branch.current "green bold"
git config --global color.branch.local "white"
git config --global color.branch.remote "yellow"
git config --global color.branch.upstream "magenta"
git config --global color.branch.plain "white"
# git grep slots (git 2.0+):
git config --global color.grep.filename "magenta"
git config --global color.grep.linenumber "yellow"
git config --global color.grep.match "red bold"
git config --global color.grep.matchContext "white"
git config --global color.grep.separator "white"
# Truecolor (git 2.26+, 2020):
git config --global color.diff.new "#3fb950 bold"
git config --global color.diff.old "#f85149 bold"color.decorate.<slot> — git log --decorate ref colours
git log --decorate annotates each commit with the refs that point at it (branches, tags, HEAD, stash). Each ref kind has its own slot — useful when scanning a busy history and you want branches one colour, tags another, and HEAD popping out.
# git log --decorate slots:
git config --global color.decorate.branch "green bold"
git config --global color.decorate.remoteBranch "red bold"
git config --global color.decorate.tag "yellow bold"
git config --global color.decorate.stash "magenta bold"
git config --global color.decorate.HEAD "cyan bold"
git config --global color.decorate.grafted "blue"
# Pair with a one-line graph to make refs even more legible:
git config --global alias.lg \
"log --graph --oneline --decorate --all"
# Then: git lgCanonical fully-coloured shell prompt config — bash + zsh
Git ships git-prompt.sh (in contrib/completion/) which exports __git_ps1 for bash / zsh. The coloured form (GIT_PS1_SHOWCOLORHINTS=1) renders branch / dirty / stash / upstream status in distinct colours. Below is the canonical wire-up — copy the block into ~/.bashrc or ~/.zshrc. The block does NOT use color.ui (it builds its own SGR via \[\e[...m\] brackets that bash counts as zero-width — wrong brackets break terminal line-editing).
# ~/.bashrc — fully-coloured git prompt
# (Debian / Ubuntu / Fedora ship git-prompt.sh under
# /usr/share/git-core/contrib/completion/git-prompt.sh;
# Homebrew ships it under
# /opt/homebrew/etc/bash_completion.d/git-prompt.sh.)
source /usr/share/git/completion/git-prompt.sh
# Colour hints: branch (green) / dirty (yellow) / staged (red).
export GIT_PS1_SHOWCOLORHINTS=1
# Show + for staged changes, * for unstaged.
export GIT_PS1_SHOWDIRTYSTATE=1
# Show $ if anything is stashed.
export GIT_PS1_SHOWSTASHSTATE=1
# Show % if there are untracked files.
export GIT_PS1_SHOWUNTRACKEDFILES=1
# Show ↑/↓ counts vs upstream.
export GIT_PS1_SHOWUPSTREAM="auto verbose"
# \[ ... \] tells bash these bytes are zero-width — required
# for correct line-edit wrap math. PROMPT_COMMAND lets
# __git_ps1 splice the git status into PS1 each prompt.
PROMPT_COMMAND='__git_ps1 "\[\e[36m\]\u\[\e[0m\]@\[\e[35m\]\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]" "\\\$ "'
# zsh equivalent (~/.zshrc) — drops \[ \] (zsh uses %{...%}):
# setopt PROMPT_SUBST
# source /usr/share/git/completion/git-prompt.sh
# PROMPT='%F{cyan}%n%f@%F{magenta}%m%f:%F{blue}%~%f$(__git_ps1 " (%s)") %# 'core.pager + LESS=FRX — why colours sometimes don't reach the pager
By default git pipes the output of git log, git diff, git show, git branch -a, etc. through a pager (less on most systems). The pipe is no longer a TTY — but git knows it pipes into its OWN pager and re-injects colour as if it were a TTY. The catch: less strips control characters by default and renders SGR escapes as ^[[31m literal noise. The fix is LESS=FRX — -R keeps SGR alive, -F quits if output fits one screen (so short diffs don't trap you in less), and -X skips clearing the screen (so your scrollback retains the diff after you quit). git already sets LESS=FRX automatically when it invokes its default pager — but if you override core.pager or GIT_PAGER with a custom command you need to set LESS=FRX (or pass -R) yourself.
# Inspect current pager (most systems: 'less').
git config --get core.pager
# Sane explicit form — leaves colour intact, quits on short output:
git config --global core.pager "less -FRX"
# Or set LESS globally and leave core.pager unset:
export LESS=FRX # add to ~/.bashrc
# Custom pager — REMEMBER to set the flags yourself:
git config --global core.pager "less -+F -+X -R" # don't auto-quit
# Disable the pager entirely (one-shot):
git --no-pager log
# Per-command pager override:
git config --global pager.diff "delta --side-by-side" # ships colour itself
git config --global pager.log "less -FRX +'/^commit'" # jump to first commit
git config --global pager.branch false # no pager for branch -aForcing colour through a pipe — git log --color=always | less -R
Every git command accepts a per-invocation --color={auto,always,never} flag that overrides both color.ui and the per-command key. The canonical use is piping into a renderer that ISN'T git's own pager — less -R, bat, aha (HTML conversion), or tee while keeping colour. Without --color=always, git sees a non-TTY pipe and strips colour automatically. The pipe target needs to render SGR for the bytes to be useful — less -R, bat, aha, delta, ansi2html. Without it, you'll see ^[[31m noise.
# Pipe coloured log into less manually (with -R to render SGR):
git log --color=always --graph --oneline | less -R
# Same idea with diff — useful with side-by-side viewers:
git diff --color=always | bat --paging=always
# Convert coloured diff to HTML for a code review email / blog post:
git log --color=always --graph -p HEAD~5..HEAD | aha > review.html
# Pipe coloured log into tee, keep on screen AND save to file:
git log --color=always --oneline | tee --output-error=warn /tmp/log.ansi
# Strip later when archiving (see /strip):
sed -E 's/\x1b\[[0-9;]*m//g' /tmp/log.ansi > /tmp/log.txt
# fzf with coloured input — needs --ansi flag:
git log --color=always --oneline | fzf --ansiConfiguration-key matrix
Every git colour-related config key, the values it accepts, its default, the subcommands it affects, and the git version it landed in. Keys without an explicit default fall back to color.ui.
| Key | Values | Default | Applies to | Since |
|---|---|---|---|---|
| color.ui | auto · always · never · true · false | auto | all | 1.5.5 |
| color.diff | auto · always · never | color.ui | diff · show · log -p | 1.5.0 |
| color.status | auto · always · never | color.ui | status | 1.5.0 |
| color.branch | auto · always · never | color.ui | branch · branch -a | 1.5.0 |
| color.grep | auto · always · never | color.ui | grep | 1.5.6 |
| color.interactive | auto · always · never | color.ui | add -i · add -p · rebase -i | 1.5.0 |
| color.decorate | auto · always · never | color.ui | log --decorate | 1.5.6 |
| color.pager | true · false | true | any paged output | 1.5.6 |
| color.advice | auto · always · never | color.ui | advice hints | 2.18 |
| color.push | auto · always · never | color.ui | push | 2.41 |
| color.remote | auto · always · never | color.ui | fetch · remote | 2.21 |
Related references
Adjacent pages on this site that cover the surrounding ANSI / pager / CI ecosystem.
- Strip ANSI codesAfter-the-fact regex to remove SGR bytes from a captured git log — useful when shipping a coloured log to a non-rendering aggregator.
- Common ANSI pitfallsSymptom → cause → fix for adjacent issues — pager strips colour, less renders escapes literally,
--color=alwaysreaches the wrong consumer. - ANSI in CI logsForce git's coloured output through GitHub Actions / GitLab / Jenkins log pipes with FORCE_COLOR / --color=always / a PTY wrapper.
- ANSI in the wildWhere ANSI bytes show up in real systems — container logs, asciinema casts, log shippers, dotfile frameworks — and how to decode each.