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=always` reaches 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.