Guide
git diff, explained
One command, four comparisons: working tree, index, branches and commits. This guide covers what git diff compares by default, the variants you'll use daily, and how to make the output readable when it's prose or data instead of code.
What plain git diff compares
Plain git diff compares your working tree against the index: it shows edits you have not staged yet. Once you git add something, it leaves this view. The other two everyday forms: git diff --staged shows what is staged against the last commit (what would be committed right now), and git diff HEAD shows both at once, everything uncommitted.
How to diff staged changes
git diff --staged shows exactly what your next commit will contain: the index compared with HEAD. --cached is an older name for the same option. If plain git diff prints nothing after git add, this is the diff you're looking for.
Diff between two branches
Name the two branches and git compares their tips. Add a path to narrow it to one file. The three-dot form answers a different question: not "how do these branches differ" but "what did this branch change since it split off", which is what a pull request will contain.
Diff between two commits
Single files and arbitrary files
How to see what's in a stash
git stash show on its own prints only a file summary. Add -p to see the full diff of a stash against the commit it was made on.
git stash show -p is worth memorising: it lets you check what a stash contains before deciding whether to apply it, instead of applying it to find out.
The flags worth knowing
| Flag | What it does |
|---|---|
| --stat | Summary per file: how many lines added and removed |
| --name-only | Just the changed file names |
| --word-diff | Mark changed words instead of whole lines; the terminal's best answer for prose |
| -w | Ignore whitespace changes |
| --staged | Compare the index against HEAD instead of the working tree against the index |
| --no-index | Compare two files that aren't in a repository |
Cheat sheet
| Task | Command |
|---|---|
| Unstaged edits | git diff |
| Staged edits | git diff --staged |
| Everything uncommitted | git diff HEAD |
| Two branches, tip to tip | git diff main feature |
| What a branch changed since it split | git diff main...feature |
| Two commits | git diff 4d17e0b 8f2a91c |
| The last commit, with its message | git show HEAD |
| One file only | git diff -- src/app.ts |
| Two files outside a repo | git diff --no-index a b |
| Inside a stash, without applying | git stash show -p |
When the diff is prose or data, not code
Everything above prints line diffs, and line diffs were built for code. A reworded paragraph, an edited CSV or a changed image comes out as noise or "Binary file". --word-diff helps with prose; for the rest, the terminal has no answer.
Read the change, not the diff
Meridian is a native Git client for the Mac. It opens from the terminal in under a second, renders Markdown, images and data as themselves, then lets you stage and commit.
Free 14-day trial | One licence, three Macs
Related: Git worktrees, explained | Best Git client for Mac | Meridian, a native Git client for the Mac
git diff, answered
How do I exit git diff?
Press q. git pipes diffs through a pager (usually less), and q quits it. To print without the pager, use git --no-pager diff.
How do I see staged changes in git diff?
Run git diff --staged (or its older name, git diff --cached). Plain git diff shows only unstaged edits, so it goes quiet after git add.
How do I see the diff of my last commit?
git diff HEAD~1 HEAD, or the shorter git show HEAD, which prints the last commit's message and its diff together.
Why are untracked files missing from git diff?
git diff only compares tracked content. Mark a new file with git add -N file (intent to add) and it appears in the diff as all-new content, or compare it directly with git diff --no-index /dev/null file.
What is the difference between two dots and three dots?
git diff main..feature is the same as git diff main feature: it compares the two tips. git diff main...feature compares feature against the common ancestor, showing only what the feature branch changed. For "what will my PR contain", three dots is usually what you mean.