Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~16 min· topic 5 of 6

Topic 1.5

Comparing Changes: git diff in Depth

In one line

git diff answers 'what's different between these two things?'. With no arguments it compares your files with the staging area. --staged compares staged changes with the last commit. git diff A B compares two commits or branches, and A...B (three dots) shows only what B changed since it split from A, which is what a pull request shows. Flags like --stat, --name-only, --word-diff, and -w change how the answer is shown.

0/6 · 0%

Think of it like this

Spot-the-difference puzzles. The puzzle is only useful once you know *which two pictures* you're comparing. git diff is the same: the important part is picking the two sides.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Diff
A description of the differences between two versions of files: which lines were removed and added.
Hunk
One block of changes in a diff, starting with an @@ … @@ header.
Context lines
Unchanged lines shown around a change so you can see where it is.
Two-dot (A..B)
In git diff, comparing the tip of A with the tip of B directly.
Three-dot (A...B)
In git diff, comparing the merge base of A and B with B: only B's own changes.
Merge base
The latest commit both branches share, where they split.

Step by step

01Three diffs for the three trees

Remember the three trees (Topic 0.2). Each plain diff compares two of them. Priya edits cart.js, stages part of it, then keeps editing, so each diff shows something different.

terminal
$ git diff --stat
git diff --staged --stat
git diff HEAD --stat
── expected output ──
src/cart.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
src/cart.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
src/cart.js | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
Unstaged, staged, and both together.
Three diffs for the three treesdiagram
Rendering diagram…

02Reading a hunk

Here is the staged change. The header says the hunk starts at line 18 in both versions, covering 6 old lines and 7 new ones. One line was replaced and one added.

terminal
$ git diff --staged src/cart.js
── expected output ──
diff --git a/src/cart.js b/src/cart.js
index 3f2a1b9..8c7d6e5 100644
--- a/src/cart.js
+++ b/src/cart.js
@@ -18,6 +18,7 @@ export function cartTotalPaise(cart) {
const items = sumItems(cart.items);
- const fee = 3000;
+ const fee = deliveryFeePaise(cart, cart.distanceKm);
+ const discount = couponDiscountPaise(cart);
const gst = Math.round(items * 0.05);
- return items + fee + gst;
+ return items - discount + fee + gst;
}

03Two dots vs three dots

Arjun wants to review Priya's branch. Since she branched, main gained the packaging charge. A two-dot diff compares the tips, so the packaging code appears as *removed*, which is confusing. A three-dot diff starts from where she branched and shows only her work.

terminal
$ git diff --stat main feature/coupons
git diff --stat main...feature/coupons
── expected output ──
src/coupons.js | 41 +++++++++++++++++++++
src/pricing.js | 6 +-----
2 files changed, 42 insertions(+), 5 deletions(-)
src/coupons.js | 41 +++++++++++++++++++++
1 file changed, 41 insertions(+)
Two dots vs three dotsdiagram
Rendering diagram…

04Other handy comparisons

Diff works on any two commits, limited to any paths. Long single-line changes (JSON, Markdown) are easier to read word by word.

terminal
$ git diff HEAD~3 HEAD -- src/pricing.js | head -3
git diff --name-only v1.6.2 v1.7.0
git diff --word-diff README.md
── expected output ──
diff --git a/src/pricing.js b/src/pricing.js
index 1a2b3c4..5d6e7f8 100644
--- a/src/pricing.js
src/cart.js
src/coupons.js
src/pricing.js
Delivery is [-free-]{+free over ₹500+} in Guwahati.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

"git diff shows nothing, but I changed files!"

Arjun runs git add ., then git diff to review before committing.

terminal
$ git add . && git diff
git status --short
── what you'll see ──
M src/dispatch.js
M src/eta.js
No diff output at all, yet two files are modified.

Myth vs fact

Myth

git diff main feature shows what the feature branch changed.

Fact

It compares the two tips, mixing in everything main changed too. Use main...feature for the branch's own changes.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    git diff --check warns about trailing whitespace and leftover conflict markers, and git diff --color-moved highlights moved blocks in a different colour, so refactors that move code around are much easier to review.

Remember this

  1. 1

    git diff = working directory vs staging area: changes you haven't staged yet. If everything is staged, it shows nothing, which surprises beginners.

  2. 2

    git diff --staged (same as --cached) = staging area vs last commit: exactly what git commit would record. Read this before every commit.

  3. 3

    git diff HEAD = working directory vs last commit: all your uncommitted changes, staged or not.

  4. 4

    git diff main feature (or main..feature) compares the two tips directly, so changes made on main since the branch started show up as if the feature removed them. git diff main...feature (three dots) compares from the merge base, showing only the feature's own changes, like a pull request.

  5. 5

    Reading the output: ---/+++ name the old and new file, @@ -12,7 +12,9 @@ means 'old file from line 12, 7 lines, new file from line 12, 9 lines', lines starting - were removed and + added. Unmarked lines are context.

  6. 6

    Useful flags: --stat (a summary per file), --name-only, --word-diff (changes inside long lines, good for prose and config), -w (ignore whitespace), and -- path to limit to some files. git difftool opens the diff in a visual tool.

Explain it without notes

01

What do git diff, git diff --staged, and git diff HEAD each compare?

02

Why do pull requests use a three-dot comparison?

Practice

01

Stage half of a change, then show unstaged, staged, and total changes.

02

Compare a branch with main using two dots and three dots and explain the difference.

Trade-offs

  • ↔

    Command-line diffs are fast and scriptable. Visual diff tools (git difftool, editor views) are easier for large or moved changes. Use both.

Done when you can

  • I know which trees each plain diff compares.

  • I can read hunk headers.

  • I use three dots to review branches.