Guides

How Diff Algorithms Actually Find Differences

By the Laborilo team. Last updated August 20, 2026.

A diff that marks half a paragraph as changed when only one word actually moved makes the tool feel unreliable, like it's not really showing what happened. It usually is, just not the way a human would have marked it up. A diff tool doesn't know what you changed. It's solving a search problem. Finding the shortest path between two versions of a text. And there's usually more than one shortest path.

It's a shortest-path problem, not a "spot the difference" problem

Comparing two texts line by line reduces to finding their longest common subsequence (LCS). The largest set of lines that appear in both texts, in the same order, even if other lines are interspersed between them. Everything in the first text that isn't part of that shared sequence gets marked as removed; everything in the second text that isn't part of it gets marked as added. The diff you see is really "everything except the longest common thread" dressed up as insertions and deletions.

The algorithm most tools actually run

Finding the true longest common subsequence by brute force gets slow fast as documents grow. The algorithm nearly every mainstream diff tool uses instead, including git's default, comes from a 1986 paper by Eugene Myers. It reframes the comparison as finding the shortest edit script between two sequences. The minimum number of line insertions and deletions needed to turn one into the other. By searching an "edit graph" outward from the start until the two sequences meet. It's fast in practice for the case that matters most: two versions of a document that are mostly the same with a few localized changes.

Why the "same" diff can look different

Here's the part that surprises people: for a lot of real edits, more than one minimal-length diff exists, and Myers' algorithm has to pick one using tie-breaking heuristics. Which can produce a diff that's technically correct but visually confusing, especially around blocks of repeated or blank lines. This is a known enough problem that git ships an alternative, "patience diff," which prioritizes matching unique lines first before filling in the gaps. It tends to produce more human-readable diffs on code that's been reorganized (functions moved, blocks reordered) at some cost in raw speed.

None of that means a confusing-looking diff is broken or lying about what changed. It means "shortest" and "most obviously readable" aren't always the same answer, and the algorithm only promises the first one unless you reach for a tool or mode built around the second.

Which level of diff to actually use

Everything above describes line-level diffing, which is what most code and document diff tools default to because it's cheap and matches how people read line-oriented text. Word- and character-level diffing run the same LCS logic at a finer grain, which is why a good diff tool can show that only three words changed inside an otherwise-identical paragraph instead of just flagging the whole line as different. At the cost of more computation, since the sequence being compared is much longer.

If the goal is reviewing a code change, line-level diffing is usually the right default, since it matches how the file is actually structured and read. If the goal is catching a small wording change buried in a long paragraph of prose, switch to word-level diffing so a single swapped word doesn't get lost inside a wall of red and green. And if a line-level diff looks unreadable because of how lines got reordered, that's exactly the case patience diff was built for, not a sign the comparison is wrong.

Paste two versions of a text and see exactly what moved, line by line, with the diff checker.