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 #

What differs, and between what
$ 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 #

Anatomy of a diff hunk
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 #

FlagEffect
--statSummary: files and line counts
-wIgnore whitespace-only changes
--word-diffWord-level inline changes
--name-onlyJust the file list
path1 path2Limit 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 #

What this branch brings, and what one commit did
$ 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.