git diff shows what changed before it becomes permanent. It is the review step for your own work — the difference between the working tree, the staged area, any commit, and any branch — and reading it well is the difference between "I think it works" and "I saw exactly what moved".
The four comparisons #
$ git diff # working tree vs staged (unstaged changes)
$ git diff --staged # staged vs last commit (what a commit would hold)
$ git diff HEAD # working tree vs last commit (everything)
$ git diff main feature/x # between two branches
The mental model is three places — working tree, index (staged), HEAD — and diff between any two of them. --staged is the pre-commit read: it shows exactly what the next commit will contain, which is the thing to check before committing.
Reading the output #
diff --git a/src/blog.js b/src/blog.js
index a1b2c3..d4e5f6 100644
--- a/src/blog.js
+++ b/src/blog.js
@@ -12,7 +12,7 @@ function renderIndex(env) {
- const size = 10;
+ const size = 12;
---/+++ name the old and new versions; @@ -12,7 +12,7 @@ says "seven lines starting at 12 in each"; - and + lines are the change. Three context lines surround each hunk by default — add more with -U10 when surroundings matter.
The flags that matter #
| Flag | Effect |
|---|---|
--stat | Summary: files and line counts |
-w | Ignore whitespace-only changes |
--word-diff | Word-level inline changes |
--name-only | Just the file list |
path1 path2 | Limit to specific paths |
--stat is the ten-second review — scope check before reading content. -w is honesty about real changes in a file your editor reformatted. --word-diff makes prose and config changes readable instead of line-noise.
Reviewing branches and commits #
$ git diff main...feature/toc --stat
$ git show f3e2d1c # one commit's diff, with message
$ git show HEAD~1:src/blog.js # a file as it was before
The three-dot form diffs from the merge base — what the branch adds — which is nearly always what you mean. git show on any commit reproduces it; the file-from-revision form is instant archaeology without checkout.
Changes you regret are reset and revert; changes across branches are merge and rebase. The Git series continues.
