Read the diff as an attack surface, not a summary
Read a diff the way you read untrusted input: as a representation someone chose to show you, made by a tool with defaults, cut by pipes, sized to be skimmed. Apply nothing until the tree confirms the story. This assumes you can already skills/verifying-a-claim; every check below is that shape.
Inspect the shape before any hunk
Run git diff --stat and git apply --numstat before reading lines. The file
list is the contract; the hunks are prose. A "small refactor" touching
lock.txt, a workflow file, or anything unstated is a different change wearing
this change's clothes. Generated files (vendored deps, minified JS, lockfiles)
hide the two real lines — dismiss them by name, deliberately, not by eye.
Where the format lies
Most of this is in the git-apply and diff-format man pages, in passing. The claims below were verified against git 2.54.0 on 2026-09-10.
Context is three lines. A hunk shows ~3 lines around each change plus a
function name in the @@ header. That name is a regex you can redefine per
language (gitattributes' hunk-header); it can name the wrong construct. Code
four lines off the changed line is invisible. Read the whole file post-apply,
not the hunks.
Whitespace flags delete meaning. git diff -w collapsed a change of Python
indentation (return moving a nested block) to a zero-line diff. Indent is
control flow in some languages, and in any language -w/--ignore-space-change
is a claim that the whitespace change is noise — made by whoever ran the
command, not by you. Review whitespace changes as content.
Renames are a threshold, and mode changes are a line you skim past. Rename
detection reports a similarity index — below threshold, a moved-and-edited
file renders as delete-plus-new-file and its whole history detaches from your
view. And old mode 100644 / new mode 100755 is a real change with no hunks
at all: a script made executable, a setuid bit. Grep the raw patch for mode
and rename rather than trusting the stat.
Moved code hides changed code. The diff algorithm pairs identical lines, so
a block that moved and got edited in passing can render as pure additions in
the new location — no - lines, nothing to react to. --color-moved exists
because this is common enough to need highlighting.
Truncated hunks are valid patches. Cut a two-file patch just before the
second diff --git line and git apply succeeds, rc=0, having silently not
made the second file's change. Anything piped through head, less, or a
context-overflowing agent transcript is a different diff from the one on
disk. Compare --numstat output of the patch file against the patch you were
shown; count diff --git lines.
Hunk counts are trusted, not checked. Tamper a number in @@ -1,3 +1,3 @@
and git apply says corrupt patch (rc=128); --recount exists for patches
hand-edited without adjusting counts. Needing --recount is itself a signal:
someone edited the patch.
When not to apply
git apply --check(ideally with--3way, so the index blob hashes in theindexline get verified, not just the text) fails or was not run. A check you skipped has unknown, not clean, state.- The patch touches paths outside the working tree. git rejects this by
default and calls the override
--unsafe-paths; the name is the warning. - The diff was written by the thing that wants it applied. Diff the tree
(
git diff HEADon a scratch apply), never the artifact you were handed. The man page warns a patch that renamesa→bandb→acorrupts files if applied file-by-file — ordering is part of what you cannot see. git apply --rejectwas needed. Partial application is not the change.
The pair
Your reading and a scanner disagree in opposite directions — you see intent and miss the glob of moved code that added a dependency; it sees the shape and misses the sentence that redefined the word "trusted". Do not average them. skills/review-and-scanner-fail-opposite shows which one to believe per finding.
Sources: git-apply and diff-format man pages (git-scm.com), and demos on git
2.54.0 (truncation, recount, -w-erases-indent, mode changes), all
2026-09-10; HN threads 47169518 and 48980193 on reviewer fatigue with
agent-authored diffs, 2026-09-10.