git diff is the most frequently used investigation command. Know its four
modes and you understand what lives in which Git zone.
Four main modes
git diff # working tree vs index (what is not yet staged)
git diff --staged # index vs HEAD (what goes into the next commit)
git diff HEAD # working tree vs HEAD (sum of both)
git diff <A> <B> # commit A vs commit B
These are the four Git zones and the pairs between them (see chapter 5 of the textbook).
Common scenarios
# What you have not staged yet
git diff
# What goes into the next commit
git diff --staged
# synonym: git diff --cached
# Everything that differs from the last commit
git diff HEAD
# What changed between releases
git diff v1.0 v1.1
git diff v1.0..v1.1 # equivalent
# Only within a directory
git diff -- src/auth/
git diff HEAD -- "**/*.py"
# Between two branches
git diff main feature # all differences between tips
git diff main...feature # only what feature added relative to merge-base
The difference between git diff A B and git diff A...B is subtle:
A Bis the diff between tips. "What changes would turn A into B."A...Bis the diff from the common ancestor to B. "What did B add, ignoring parallel changes in A."
For code review A...B is more useful: a clean picture of "what the
feature did" without noise from main.
Useful options
git diff --stat # summary: files and line counts
git diff --shortstat # single summary line
git diff --name-only # only the list of changed files
git diff --name-status # list + status (A/M/D/R)
git diff -w # ignore whitespace
git diff --word-diff # diff by words, not lines
git diff --word-diff=color # with color highlighting
git diff -M # detect renames
git diff -C # detect copies
git diff -B # break-rewrite: split a heavily
# changed file into delete+add
git diff --find-renames=50% # similarity threshold for renames
git diff -p # full patch (default)
git diff -U10 # 10 lines of context (default is 3)
git diff -U0 # no context, only the changed lines
Pickaxe and content search
Not exactly git diff, but closely related: git log -S and -G:
git log -S "magicConstant" --oneline # commits that changed the
# number of occurrences of a string
git log -G "TODO\(.*\)" --oneline # commits whose diff matches a regex
See log.
Comparing files outside a repository
git diff --no-index a.txt b.txt
Useful as a general-purpose diff with colors and filters, even when the files are not in Git.
Pitfalls
git diffwithout arguments does not show staged changes. If it looks like there are no changes but you staged something, rungit diff --staged.- Binary files appear as
Binary files differ. To see their names, use--stator--name-only. To force text output, add--text. - Files with non-UTF-8 encodings (windows-1251, etc.) may display as
garbage. Fix this with
.gitattributesand a custom diff driver, or convert the files before diffing. - Long lines in JSON or minified JS are shown as one line and are
unreadable.
--word-diffsometimes helps. - Diffing a large file is slow.
--statis the fastest option.