How Diff Algorithms Actually Compare Text
By Marcus Vane · August 31, 2026 · Developer Tools
A diff does not know what you changed. It finds the smallest edit script that explains the difference, and understanding that explains every confusing diff you have ever read.
Everyone who has reviewed a pull request has seen a diff that made no sense: a function apparently deleted and recreated identically, or a change to one line reported as a change to twelve. These are not bugs. They follow directly from what a diff algorithm is actually computing.
The longest common subsequence
A diff tool does not observe your edits. It receives two documents and finds the longest sequence of lines that appears, in order, in both. Everything outside that sequence is reported as a deletion from the first or an insertion into the second. There is no concept of "moved" or "renamed" in the base algorithm, only removed and added.
This immediately explains the most confusing behaviour. Move a block of code from the top of a file to the bottom and the tool reports a deletion and an unrelated insertion, because a moved block cannot be part of an in-order common subsequence.
Granularity changes everything
Most tools compare line by line, which is efficient and matches how code is written. The cost is that changing one word marks the whole line as replaced. Word-level and character-level diffs are far more readable for prose, at the price of noisier output on structured text. Choosing the right granularity for the content type is the single biggest improvement most people can make to their diff reading.
Whitespace and line endings
Two files that look identical can diff as entirely different if one uses Windows line endings and the other Unix, because every line differs by an invisible character. Reformatting a file changes indentation on every line and buries the one real change in hundreds of cosmetic ones. This is why teams separate formatting commits from logic commits.
Reading a diff efficiently
- Set the granularity to match the content: line for code, word for prose.
- Enable whitespace-insensitive comparison first to see whether any substantive change exists at all.
- Normalise line endings before comparing files from different operating systems.
- Look at the shape of the diff before the content: large paired deletions and insertions usually indicate a move.
- Increase context lines when a change depends on surrounding code.
- Review formatting changes separately from behavioural ones.
Common mistakes
- Assuming a large diff means a large change.
- Comparing a file against a version that was already reformatted.
- Ignoring trailing whitespace differences that will nonetheless cause a merge conflict.
- Using a character-level diff on minified code, which produces unreadable output.
- Trusting a visual diff of rendered output rather than the source when debugging.
Wrapping up
A diff is an explanation, not a recording. Once you know it is searching for the longest shared sequence, the strange output becomes predictable and easy to read past.
Compare two versions of any text side by side.
SwiftMultiTool — free online tools for everyone. Home · Blog · About · FAQ · Contact