Blog

How a Diff Actually Works

2 September 2026

Comparing two versions of a text sounds like it should be trivial — surely you just walk through both and note where they disagree. But the moment one side has an extra line, a naive walk falls permanently out of step and reports everything after it as different. A real diff has to answer a harder question: what is the most of these two texts that can be considered the same?

The longest common subsequence

Every diff tool is built on the same idea: find the longest sequence of content that appears in both texts, in the same order — the longest common subsequence. Everything in that sequence is "unchanged". Whatever is left over in the old text was removed; whatever is left over in the new text was added. The highlights you see are just the leftovers.

"In the same order" is the phrase doing the work. The common sequence is allowed to skip over things, but never to backtrack. That single constraint explains most of what people find surprising about diff output.

Why moved text shows as delete-plus-add

Move a paragraph from the top of a document to the bottom and the diff reports it removed from the top and added at the bottom — as if you had deleted it and written it again from scratch. That is the no-backtracking rule at work: the paragraph cannot be part of a sequence that runs in order through both versions, because its positions disagree about the order. A diff has no concept of "the same text, elsewhere"; it only knows in-sequence and out-of-sequence.

The same logic explains why a line that was edited shows as a removal plus an addition rather than as "changed": to the algorithm, the old line and the new line are simply two different lines. Tools that display "modified" lines are running a second, finer diff inside the delete/add pair after the fact.

Lines, words, or characters

Before comparing anything, the text is chopped into units, and the choice of unit changes what "the same" means. Line mode is the default for the same reason version control uses it: a line is the unit people edit, and comparing a few hundred lines is fast no matter how long they are. Its weakness is prose — fix one word in a long paragraph and the whole paragraph lights up as removed-and-added, because the paragraph is one "line".

Word mode fixes exactly that, highlighting just the word that changed. Character mode is the finest-grained and is mostly useful for spotting a one-letter change inside a word or an invisible character. The finer modes pay for their precision in speed — which is why our tool switches very large inputs back to line mode rather than letting the page freeze.

When everything is "different" and nothing looks it

The most common diff surprise is two texts that look identical but light up as entirely changed. The cause is almost always characters without glyphs. Windows ends lines with a carriage return plus a line feed, Unix with a line feed alone — so text that took a round trip through different systems differs invisibly on every single line. Trailing spaces, tabs versus spaces, and the non-breaking spaces that word processors and web pages love to paste do the same thing.

Character mode is the debugging tool here: the highlight sits precisely on the invisible character, at the end of a line or in the middle of a "space".

Reading a unified diff

The "Copy unified diff" button produces the format version control speaks: lines prefixed - were removed, lines prefixed + were added, and each cluster of changes sits under a header like @@ -3,5 +3,6 @@ — old text starting at line 3 spanning 5 lines, new text starting at line 3 spanning 6. The unprefixed lines around each change are context, included so the change can still be located if the surrounding file has shifted. It is the same format git diff emits, and tools can apply it mechanically to reproduce your edit.

FAQ

Why does moved text show up as a deletion plus an addition?

Because a diff only knows two states: part of the common sequence, or not. It finds the longest run of content that appears in both texts in the same order; anything outside that run is marked removed from one side and added to the other. A paragraph that moved breaks the order, so it falls outside the common sequence in its old position and outside it again in its new one. The tool has no concept of "the same text, elsewhere".

Why do diff tools compare lines instead of characters?

Because a line is the unit people edit and review. A character-level diff of two versions of a file is technically more precise but visually useless — hundreds of tiny highlights instead of "this line changed". Line mode also matches how patches are applied: version control tools like Git work line by line for the same reason. Word and character modes earn their keep on prose, where a single-word edit inside a long paragraph would otherwise flag the whole paragraph.

Why does my diff show every line as changed when the files look identical?

Almost always invisible characters. The usual culprit is line endings — Windows ends lines with CRLF and Unix with LF, so every line differs by one invisible carriage return. Trailing spaces, tabs versus spaces, and non-breaking spaces pasted from a web page or word processor do the same thing. The text looks identical because the characters that differ have no glyph.

What is a unified diff?

The standard text format for describing changes, the one version control tools produce. Removed lines are prefixed with a minus, added lines with a plus, and each group of changes sits under an @@ header giving the line numbers where it applies, with a few unchanged context lines around it so the change can be located even if the file has shifted. It is both human-readable and machine-applyable, which is why it became the lingua franca of code review.

Related guides

Try it now: Free Diff Checker

Tools from this guide

Diff Checker Compare two texts line by line, word by word.