Diff tools feel like magic — paste two versions, watch the changes light up. Underneath sits one elegant algorithm problem: finding the longest sequence two texts share. This explainer covers line diffs, word refinement, the Myers algorithm in plain terms, and how to read (and export) the output.
Comparing two texts by eye fails in a predictable way: everything looks the same except the part you cannot find. A diff tool inverts the job — instead of reading both documents, you read only the changes, presented in context. The question the tool must answer is subtler than it first appears, because "what changed" is not unique: several different sets of deletions and insertions transform one text into the other, and the tool's real skill is choosing the set a human would choose.
The standard framing is the longest common subsequence (LCS): the longest sequence of lines (or words) that appears in both versions, in the same order, not necessarily adjacently. Everything in the LCS is "unchanged"; everything outside it is a deletion from the old or an insertion into the new. Diff quality is LCS quality plus presentation.
Key takeaways
- A line diff finds unchanged lines; a word diff then refines inside changed line pairs to show exactly which words moved.
- Smaller is righter: the best diff is the one with the fewest total changes that still reads naturally — the minimal edit script.
- Ignoring whitespace or case is a lens, not a lie: it answers "did the content change?" separately from "did the formatting change?"
- Unified diff output (with - and + lines and @@ hunks) is the portable format developers exchange as patch files.
LCS, worked on six lines
Take an old version — alpha, bravo, charlie, delta, echo — and a new one — alpha, charlie, delta, foxtrot, echo. The longest common subsequence is alpha, charlie, delta, echo: four lines that survive in order. The diff is therefore minimal and obvious: delete bravo after alpha, insert foxtrot before echo. Notice the algorithm never "sees" bravo and foxtrot as related; replacement is not a primitive in diff-land — a changed line is always a deletion plus an insertion, and it is the word-level pass that later shows the two are counterparts.
Computing LCS exactly for two files of n and m lines is, naively, an n×m comparison problem — fine for documents, painful for hundred-thousand-line files. The Myers algorithm, which powers GNU diff and most tools since, reframes the search as finding the shortest path through an edit graph and runs in time proportional to the number of differences rather than the size of the files. That is the practical reason diffs are instant on huge files that barely changed, and slow only when nearly everything changed.
The second pass: from lines to words
Line diffs alone give clumsy reading for prose and config alike: change one word in a long line and the whole line flags as removed and re-added. Good tools therefore pair up adjacent deleted/inserted lines and run the same LCS trick inside them at word (or character) level, highlighting only the words that truly differ. Two tuning decisions separate helpful word diffs from confetti: treating punctuation as part of its word or as separate tokens, and refusing to pair lines that are too dissimilar — a threshold below which the honest presentation is "this left; something else arrived".
Character-level diff is the extreme of the same idea. It is the right lens for very short strings (a URL, a hash, a product code) and the wrong one for prose, where a single inserted word shifts every subsequent character alignment and the highlight becomes noise. Choose the granularity that matches the unit your reader thinks in.
Reading unified diff like a native
--- draft-v1.txt
+++ draft-v2.txt
@@ -12,4 +12,4 @@
The committee met on Tuesday
-to approve the draft budget.
+to approve the final budget.
Members raised no objections.
The header names the old and new files. Each hunk header (@@) gives coordinates: in the old file it starts at line 12 and spans 4 lines; in the new file likewise. Lines prefixed with a space are context — unchanged anchors the tool includes so a reader (or a patch program) can locate the change — minus lines exist only in the old version, plus lines only in the new. Three lines of context is the customary compromise between brevity and locatability. If you can read this format, you can read the output of every version control system on earth, because they all speak it.
Options that change the answer, honestly
- Ignore whitespace: re-indentation and line-reflow stop shouting. Essential for code reviews after a formatter run; dangerous if whitespace is the content (Python, YAML, poetry).
- Ignore case: answers the content question for prose edited for style. Keep it off anywhere case carries meaning — code, case-sensitive data, German nouns if you are feeling precise.
- Side-by-side vs unified: presentation only. Side-by-side suits prose and screens; unified suits patches and anything a machine will apply.
- Minimal vs default algorithms: some tools offer a "minimal" mode that works harder for fewer changes. The results occasionally differ — a reminder that "the diff" is an editorial choice, not a fact of nature.
Mistakes and pitfalls
Diffing the file against itself after a format conversion
A PDF-to-text extraction, a Word export and the original will differ in line breaks, spacing and ordering throughout — the diff becomes a wall of non-changes. Normalise both sides to the same plain representation before comparing, or compare at word level with whitespace ignored.
Treating a moved paragraph as a mystery
Basic diff has no concept of "moved": a cut-and-pasted block shows as a deletion plus a distant insertion, which is correct but easy to misread as two changes. When reviewing, scan insertions for text you saw deleted earlier before concluding anything was rewritten.
Counting changed lines as a measure of how much work happened
Reflowing a paragraph can flag fifty lines for a one-word edit, and a one-character change to a config value can alter a system's behaviour completely. Diff volume measures surface turbulence, not importance.
Common questions
Why did the tool pair my changed line with the wrong partner?
Pairing heuristics match deleted and inserted lines by similarity. When several similar lines change at once (a list of near-identical items), pairings can cross. Read the highlights with that in mind — or compare with a smaller, isolated excerpt to get unambiguous pairing.
Can a diff show changes inside images or PDFs?
Not meaningfully: diff is a text algorithm. Binary and rich formats must be reduced to text first (an OCR pass, a text extraction, source markup), and the quality of the diff then depends on the quality of that reduction.
What is a patch, exactly?
A patch is a unified diff saved as a file, addressed to a specific original. Patch programs (and git apply) replay its deletions and insertions onto a matching copy — matching being enforced by the context lines, which is why context exists.
To wrap up
Strip away the colours and a diff tool is one classical algorithm making one editorial judgement: the longest thing both versions agree on is the story, and everything else is the news. Read diffs that way — context first, highlights second — and no revision will ever hide from you again.
Try it yourself
The diff checker compares two texts by line and then by word, with ignore-whitespace and ignore-case options, and exports the result as a patch you can keep.