DEV Community

zhihu wu
zhihu wu

Posted on

Four Ways a Git Diff Lies to You (and How to Catch Each)

Every code review is a promise: this is what changed. Most days the tooling keeps that promise. Sometimes it quietly breaks it, and the break is subtle enough to survive approval.

Four diff blind spots I keep running into — each one makes a change set look bigger, smaller, or simply different than reality.

1. Two dots and three dots are not the same comparison

git diff main..feature     # tip vs tip
git diff main...feature    # merge-base vs tip
Enter fullscreen mode Exit fullscreen mode

main..feature compares the two branch tips directly. main...feature (three dots) compares from the merge base — the last commit both branches share. GitHub pull requests show you the three-dot view.

So if you review locally with two dots after main has moved on, you see every commit merged into main since the branch split — none of which your PR touched. A 12-line PR suddenly reads like 400 lines. When a change count looks absurd, check the dot count before you blame your own branch.

2. Plain git diff only shows unstaged changes

git diff compares the working tree against the index. Run git add and those edits drop out of that comparison entirely — the diff goes quiet while your changes are still there. Use git diff --cached for staged work, or git diff HEAD to see both at once.

Untracked files are a harder case: brand-new files never appear in any git diff output. Only git status lists them.

3. A moved file arrives as a delete + add

Rename detection is a heuristic, not a fact. Move a file with plain mv and the diff shows a 300-line deletion plus a 300-line addition — so a reviewer's eye slides past the four lines you actually edited.

git diff -M --stat
someFile.ts | 2 +-
similarity index 98%
Enter fullscreen mode Exit fullscreen mode

-M turns rename detection on explicitly (tune with -M40% if a heavily edited move is missed). --stat gives you the one-line summary that makes the real edit visible again.

4. That "whole file changed" diff is formatting, not data

Minified vs pretty JSON, CRLF vs LF, reordered keys: a one-field change to a 200-line API response renders as the entire file. Normalize both sides before comparing — jq -S for key order, a formatter for whitespace, dos2unix for line endings — and then everything left in the diff is real.

And when the two versions don't live in a repo at all (a log viewer, a chat message, a CMS), there's no file to run diff on. I paste both sides into CodeToolbox's diff checker — it runs in the browser, uploads nothing, and shows the added/removed lines plus a summary count before you scroll.

Blind spot 1 is the expensive one: the extra lines are real commits, just not yours. Check the dot count first.

Top comments (0)