How to read a diff like a developer
24 Sep 2026 · Text · 6 min read
Diffs are everywhere once you start looking: the red-and-green view when someone proposes a change to a document, the "compare" screen in a code review, the patch file a colleague emails you. They're all the same thing — a precise description of how to turn one text into another — and they're written in a format from the 1970s that hasn't needed to change since, because it got the job exactly right. This article teaches you to read that format fluently: the headers, the hunk markers, and the three kinds of lines.
The idea in one paragraph
A diff doesn't show you two files. It shows you the edits that turn the old file into the new one, surrounded by just enough unchanged context to locate each edit. Lines starting with a space are context — they didn't change. Lines starting with - were removed. Lines starting with + were added. That's 90% of it; everything else is bookkeeping so the edits can be found and applied mechanically.
Anatomy of a unified diff
The standard format is called "unified diff". A small one looks like this:
--- shopping-list.txt +++ shopping-list.txt @@ -1,4 +1,5 @@ milk eggs -bread +wholegrain bread +butter cheese
Reading top to bottom: the --- line names the old file, the +++ line names the new file. Then comes a hunk — one contiguous block of changes — introduced by the header @@ -1,4 +1,5 @@. The hunk shows 4 lines of context and change: "milk" and "eggs" unchanged, "bread" removed, "wholegrain bread" and "butter" added, "cheese" unchanged. Apply those edits and the old file becomes the new one.
Decoding the hunk header
The header @@ -1,4 +1,5 @@ is the part that looks intimidating and isn't. It has two halves:
| Part | Means |
|---|---|
| -1,4 | In the OLD file, this hunk starts at line 1 and covers 4 lines |
| +1,5 | In the NEW file, this hunk starts at line 1 and covers 5 lines |
That's it. The old side had 4 lines here, the new side has 5 — the difference of one tells you this hunk added a net of one line before you even read it. (When a hunk covers exactly one line, the ",1" is omitted: @@ -7 +7 @@ means line 7 on both sides.) Sometimes there's trailing text after the second @@ — that's the name of the function or section the hunk sits in, added as a courtesy for human readers; tools ignore it.
Walking through a real multi-hunk example
Real diffs have several hunks. Here's one for a recipe file, with two separate changes:
--- pancake-recipe.txt +++ pancake-recipe.txt @@ -3,7 +3,7 @@ 2 cups flour 2 tbsp sugar -1 tbsp baking powder +1 tsp baking soda 1/2 tsp salt 2 eggs 1 1/2 cups milk @@ -14,6 +14,8 @@ Heat the pan. Pour 1/4 cup batter. +Wait for bubbles on the surface. +Flip once, not twice. Cook until golden. Serve warm.
Hunk one (lines 3–9): a substitution — baking powder out, baking soda in. One line removed, one added, net zero; the counts -3,7 and +3,7 are equal, confirming it. Hunk two (old lines 14–19, new lines 14–21): a pure insertion — two lines added after "Pour 1/4 cup batter", nothing removed. The new side covers 8 lines versus the old side's 6. Notice how the context lines ("Heat the pan", "Cook until golden") let you locate each change without line numbers — that's their entire job, and it's why diffs stay readable when files are thousands of lines long.
Unified versus side-by-side
Unified diff (above) interleaves old and new in one column — compact, great for small changes, and the only format that works in an email or a patch file. Side-by-side puts old on the left and new on the right, which is easier on the eyes for reviewing prose but needs twice the width and falls apart on narrow screens. Underneath, they're the same information: every tool that shows one can show the other. When a change is confusing in one view, switching views often un-confuses it — a substitution that looks like two separate edits in unified view is obviously one edit when the lines sit next to each other.
Word-level highlighting: reading inside the line
Line diffs have a blind spot: when a 200-word paragraph changes by one word, the whole paragraph lights up as removed-and-added. Good diff tools add a second pass that highlights the changed words inside changed lines — the rest of the paragraph stays dim, and the single altered word glows. If your tool offers it, turn it on; it converts "something in this paragraph changed, good luck" into "this word changed", which is usually the entire review.
Gotchas that confuse everyone exactly once
- Moved code looks like delete + add. Diff algorithms compare text, not intent. Cut a paragraph from page 1 and paste it on page 5, and the diff shows a deletion and an addition — it has no notion of "moved". Some tools detect this; most don't.
- Whitespace-only changes are invisible but real. A diff with "ignore whitespace" turned on will hide trailing-space cleanups and tab-to-space conversions. If a diff looks empty but the tool insists something changed, whitespace is the prime suspect.
- "No newline at end of file". You'll see this marker when one version ends with a newline and the other doesn't. It's a one-byte difference that looks like line noise — now you know what it means.
- Binary files just say so. "Binary files differ" is the whole diff. There's nothing to read; use a tool built for that format instead.
- Big refactors look terrifying. Renaming a variable used 300 times produces 300 changed lines. The diff is faithfully reporting a trivial change at scale — read the pattern once, then skim.
Patch files: diffs you can apply
A diff with proper ---/+++ headers isn't just readable — it's executable. Save it as a .patch or .diff file and the patch command (or git apply) will perform every edit on a copy of the old file, using the context lines to find each hunk even if the file has shifted slightly since. That's why the headers and hunk markers exist in exactly this format: the human-readable view and the machine-applicable patch are the same text. Email a unified diff to a colleague and they can apply it sight unseen; that's been the workflow of open-source development for decades. When you see a diff, you're looking at both a description and a program.
The honest caveat
A diff shows what changed in the text, never why. "Changed 18 to 20" might be a bug fix, a requirement change, or a typo — the diff can't tell you, which is why good changes come with a sentence of explanation attached. Read diffs for what, and ask humans (or commit messages) for why. And remember the tool's limits: line-based diffs can't show you that two distant edits are actually one logical change, and no diff can show you the change someone didn't make but should have.
Learn the three line types and the hunk header and you're fluent. Everything else — side-by-side views, word highlighting, patch files — is the same information in fancier clothes.