Skip to content

Text Diff Tool

Compare two blocks of text. Choose line, word, or character granularity.

A text diff compares two pieces of text and highlights what changed. The tool above runs the comparison in your browser; nothing leaves your machine. The interesting question is how a diff is computed — there’s no single right answer, and different tools make different tradeoffs.

The core problem

Given two sequences of lines, find the shortest edit script — the smallest set of insertions and deletions — that turns the first into the second. Equivalently: find the longest common subsequence (LCS), then everything not in the LCS is a change.

A: The quick brown fox
   jumps over the lazy dog
   and runs away

B: The quick brown fox
   leaps over the lazy dog
   and runs away

The LCS is lines 1 and 3. Line 2 differs, so the diff reports: line 2 deleted from A, line 2 inserted in B.

Myers’ diff algorithm

The standard line-diff algorithm is Myers’ diff, published in 1986 — it’s what git diff, diff -u, and most text editors use. It runs in O((N+M)D) time where D is the number of differences. When the inputs are mostly similar (small D), it’s near-linear; when they’re entirely different (large D), it degrades to roughly O(N²).

Myers’ produces the minimum edit script, but minimum isn’t always the most readable. Two changes inside a function can be reported as “delete the whole function, insert a new function” if that’s shorter than reporting the individual line changes. Tools like git --histogram-diff and git --patience-diff use heuristics to prefer human-readable diffs over strictly minimal ones.

Line, word, character

Most diff tools operate at multiple granularities:

LevelComparesUsed for
LineWhole lines as atomsCode review, version control
WordWhitespace-delimited tokensProse editing, when whitespace is meaningful only at word boundaries
CharacterIndividual charactersTight edits where a typo or single-character change matters

The standard approach: do a line diff first to find changed regions, then do a word or character diff inside the changed regions to highlight what specifically moved. This is what git diff --word-diff and editor “inline diff” views do.

Unified vs side-by-side

Two ways to render a diff:

  • Unified diff — the classic +/- per line format, with a few lines of context. Compact, scriptable. The format git diff and diff -u emit. Easy to copy into a code review.
  • Side-by-side — two columns, original on the left, modified on the right, changes highlighted. Easier to scan for human review, especially when changes are large or spread out.

The tool above uses a unified-style view: line mode lists every line with +, - or two spaces (no context trimming), and word or character mode shows one merged text with removals struck through and additions highlighted. There’s no side-by-side view.

What diffs can’t see

  • Renames. A diff between two files only knows about those two files. If you renamed a file and made small edits, a file-level diff sees a wholesale delete and a wholesale insert. Git’s diff layer adds rename detection (-M flag) that compares similarity scores between deleted and added files; standalone diff tools usually don’t.
  • Block moves. Move a function from line 50 to line 200 of the same file and the diff shows a delete at 50 and an insert at 200. To recognize this as “the same code, relocated” requires post-processing — git diff --color-moved does this, plain diff does not.
  • Semantic equivalence. Reformatting (changing indentation, reordering object keys, normalizing whitespace) shows up as changes even when behavior is identical. JSON-aware diff tools like jd or YAML-aware ones operate on parsed structure rather than raw text. For raw JSON specifically, see JSON diff.
  • Three-way merge. Two-way diff says what changed; it doesn’t tell you how to combine two divergent edits of a common ancestor. That’s a merge tool, not a diff tool.

Whitespace handling

Whitespace differences are real changes — and noisy ones. Most diff tools provide flags to ignore them:

  • Ignore trailing whitespace — common default. End-of-line spaces are rarely meaningful.
  • Ignore all whitespace — use carefully. if(x) and if ( x ) are equivalent in most languages but not all (Python whitespace is significant; Make depends on tabs).
  • Ignore line ending differences — \r\n vs \n. Common when files cross between Windows and Unix.

The tool above compares text exactly — it has no ignore-whitespace option, so strip trailing spaces or normalise line endings first if they aren’t the change you’re looking for.

Common pitfalls

  • Diffing minified files. Minifiers strip whitespace and rename variables; the line-level diff is one giant change. Pretty-print or beautify before diffing — see JSON formatter, HTML formatter, CSS formatter.
  • Diffing files with different line endings. A diff that shows every line as changed when the visible text is the same is almost always a \r\n vs \n issue. Normalize first.
  • Diffing across encodings. UTF-8 vs UTF-16 vs Latin-1 looks like a total change at the byte level. Decode to a common encoding first.
  • Reading the wrong direction. Diff tools have a convention — - is the first input, + is the second. Some tools use the reverse. If a diff looks backwards, check which input is which.

For structured-data diffs that ignore reformatting, see JSON diff.