← All 151 books diff, one comparison per page
One comparison per page

diff, one comparison per page

Twenty-eight lessons on the diff command, one comparison concept or one diff skill per page: the line-by-line comparator that reports the smallest set of changes; the normal format's add, delete and change commands with real line ranges; the unified format's hunks, @@ header, minus and plus lines and three lines of context; the context format as the older cousin; the dash for stdin, directories and -r trees; -q with -s for same-or-different verdicts; ignoring honestly with -i, -b and -w; the exit law of 0, 1 and 2 and the && trap it sets in scripts; cmp byte by byte and comm for sorted files; patch with offsets, fuzz and reversed patches, read before applied; ed scripts; the family in the wild; and teaching a friend one hunk in one sitting.


Steve Hodgkiss 7 lessons

One comparison, one page, one honest read. That's the rhythm.

diff, one comparison per page

Twenty-eight lessons on the diff command, one comparison concept or one diff skill per page: the line-by-line comparator that reports the smallest set of changes; the normal format's add, delete and change commands with real line ranges; the unified format's hunks, @@ header, minus and plus lines and three lines of context; the context format as the older cousin; the dash for stdin, directories and -r trees; -q with -s for same-or-different verdicts; ignoring honestly with -i, -b and -w; the exit law of 0, 1 and 2 and the && trap it sets in scripts; cmp byte by byte and comm for sorted files; patch with offsets, fuzz and reversed patches, read before applied; ed scripts; the family in the wild; and teaching a friend one hunk in one sitting.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

Every fact in this book is as the official source states it, fetched and read during this build: the local manual pages diff(1), patch(1), cmp(1) and comm(1) (GNU diffutils 3.10, GNU patch 2.7.6, GNU coreutils 9.4), the definition of truth for this book, and the Wikipedia articles Diff, Patch (Unix), Cmp (Unix), Sort (Unix), Standard streams, Pipeline (Unix) and Regular expression. No facts are sourced from Reddit, Stack Overflow, vendor blogs or commercial sites. Every command and output pair was run on this machine with temporary files under the build scratch directory only, each capture cached verbatim so the pair is reproducible. SAFETY LAW: no file outside the book directory's scratch area was written by any demonstration; patch wrote only to scratch copies, and every patch check ran with --dry-run first. Honest notes: the Wikipedia titles Diff_utility, Comm (Unix), Uniq (Unix) and Unified diff format are redirects, so their subjects are covered by the Diff article and the local manual pages instead. An independent guide, not affiliated with or endorsed by the Free Software Foundation, the IEEE, or the Wikimedia Foundation.

Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · What diff is
c is for changed4
Part 2 · The unified format
The @@ header5
Part 3 · Beyond two files
Same or different6
Part 4 · Ignoring honestly
Ignored, not equal7
Part 5 · The verdict and the kin
comm, three columns8
Part 6 · patch applies hunks
Offsets and fuzz9
Part 7 · The honest craft
Teaching diff10

Per the Wikipedia Diff article, c indicates changed, the line number of the original file appears before the single-letter code and the line number of the new file appears after, and the less-than and greater-than signs indicate which file the lines appear in. Per the diff(1) manual page, exit status is 0 if inputs are the same, 1 if different, 2 if trouble. This machine's capture: diff old_chg.txt new_chg.txt printed 2c2, then < beta, a divider of three dashes, then > BETA, and exited 1.

Comparison tools companion · No. 01
the change command

c is for changed

2c2: replace via a divider

the change command, decoded$ diff old_chg.txt new_chg.txt2c2replace block with block,a divider of three dashes,and the counts may differ< beta---> BETAold on the left, new on the rightc is for changed: one block out, one block in, three dashes between

The third letter, c, indicates changed: a block of file one replaced by a block of file two, a divider of three dashes between them.

Our capture: diff old_chg.txt new_chg.txt printed 2c2, then < beta, the divider, then > BETA. One line each side; the two counts can differ.

Old line 2 becomes new line 2. Matching counts are coincidence, not law: the ranges say exactly what they say.

ONE HONEST HOUR

Change one word in a copy, run diff, and label the < and > lines by hand.

Per the Wikipedia Diff article, a hunk begins with range information surrounded by double at signs, a minus symbol precedes the range for the hunk of the original file and a plus symbol precedes the range for the new file, each hunk range is of the format l,s where l is the starting line number and s is the number of lines the change hunk applies to, and if hunk size information does not correspond with the number of lines in the hunk the diff could be considered invalid and rejected. This machine's capture: the header read @@ -1,7 +1,7 @@, start at line 1 with seven lines, on both sides.

Comparison tools companion · No. 02
the address

The @@ header

-1,7 +1,7: two ranges, one line

two ranges, one header line@@ -1,7 +1,7 @@minus range: originalstart 1, count 7plus range: new filestart 1, count 7l is the starting line, s the count, on both sidesif the body does not match the counts, the diff could be considered invalid

Every hunk opens with range information surrounded by double at signs, per the Wikipedia Diff article. Our capture printed @@ -1,7 +1,7 @@.

The minus range belongs to the original, the plus range to the new file. Each reads l comma s: a starting line and a count.

Here both ranges say: start at line 1, hold seven lines. If the body does not match those counts, the diff could be considered invalid and rejected.

ONE HONEST HOUR

Cover the body of one hunk and reconstruct it from the @@ ranges alone.

Per the diff(1) manual page, -q, --brief reports only when files differ, and -s, --report-identical-files reports when two files are the same. This machine's captures: diff -q h_old.txt h_new.txt printed Files h_old.txt and h_new.txt differ and exited 1; diff -q on an identical pair printed nothing and exited 0; diff -s same1.txt same2.txt printed Files same1.txt and same2.txt are identical.

Comparison tools companion · No. 03
the verdict pair

Same or different

-q brief, -s says identical

two verdict flags-q briefFiles h_old.txt andh_new.txt differ-s identicalFiles same1.txt andsame2.txt are identicalthe identical pair under -q prints nothing at allsilence + exit 0verdicts: -q when files differ, -s when they match, silence plus 0 for same

Sometimes you only want the verdict. -q, --brief: report only when files differ, says the manual page. Our capture printed Files h_old.txt and h_new.txt differ.

Its quiet partner is -s: report when two files are the same; our capture printed Files same1.txt and same2.txt are identical.

The same pair under -q prints nothing at all. Silence with exit 0 is the smallest honest report a tool can give.

ONE HONEST HOUR

Run diff -q and diff -s on an identical pair and a different pair: four runs, two silences.

Per the diff(1) manual page, -i, --ignore-case ignores case differences in file contents, and exit status is 0 if inputs are the same. Per this book's plan, the closing rule of the ignore family reads: what you suppress is what you vouch for. This machine's captures: the case-blind run exited 0 while the bytes on disk never changed, and the plain run exited 1 on the same pair.

Comparison tools companion · No. 04
the honesty rule

Ignored, not equal

the verdict you chose, not truth

the honesty of ignoringexit 0 under -ia script reads: samethe bytes never changedthe rule of the family:what you suppressis what you vouch forwrite it into the commandan ignored difference is a claim about relevance, not a fact about files

Here is the honesty of the ignore flags: under -i our capture exited 0, and a script would read the pair as the same. The bytes on disk never changed.

An ignored difference is a claim about relevance, not a fact about the files. Write the flag into the command, never into your memory of the files.

Per this book's plan, the rule reads: what you suppress is what you vouch for. Every ignore flag is a small promise.

ONE HONEST HOUR

Say aloud what -i vouches for in your last comparison, then write it in the script's comment.

Per the comm(1) manual page, comm compares sorted files FILE1 and FILE2 line by line, with no options it produces three-column output where column one contains lines unique to FILE1, column two contains lines unique to FILE2 and column three contains lines common to both files, and -1, -2 and -3 suppress the matching column. This machine's captures: comm s1.txt s2.txt printed apple in column one, banana and cherry in the common column and date in column two; comm -12 printed banana and cherry; comm -23 printed apple.

Comparison tools companion · No. 05
sorted sets

comm, three columns

sorted in, three columns out

three columns, tab fencescol 1col 2col 3, commonappledatebananacherry-12 keeps common-23 keeps applesorted input is the lawunique, unique, common: the three columns of two sorted files

comm compares two sorted files line by line, says comm(1), and prints three columns: unique to file one, unique to file two, common to both.

Our capture: apple in column one, banana and cherry in the common column, date in column two. The tabs are the fences; read them as walls.

The flags remove columns: -12 kept banana and cherry, the shared lines; -23 kept apple alone. Sorted input is the law, not advice.

ONE HONEST HOUR

comm two sorted lists, then comm -12 to keep only what both hold.

Per the patch(1) manual page, when the line numbers mentioned in the patch are incorrect patch attempts to find the correct place to apply each hunk, taking the line number mentioned for the hunk plus or minus any offset used in applying the previous hunk, then scanning both forwards and backwards for lines matching the context, and if the hunk is installed at a different line from the one specified in the diff you are told the offset; -F num, --fuzz=num sets the maximum fuzz factor, the default fuzz factor is 2, and a larger fuzz factor increases the odds of a faulty patch. This machine's capture: patch --dry-run -F 2 on a file with two lines prepended answered Hunk #1 succeeded at 3 (offset 2 lines).

Comparison tools companion · No. 06
the search

Offsets and fuzz

found 2 lines off, with fuzz

found, two lines offexpected: line 11found: line 33offset 2 linesif context fails: fuzz,default maximum 2,odds of a faulty patch growHunk #1 succeeded at 3 (offset 2 lines)the dry run reports where it landeddrifted line numbers: scan for context, report the offset, distrust the fuzz

When line numbers have drifted, patch scans for a place where the context matches, the manual page says, starting from the hunk's line number plus or minus any offset.

Our capture: two lines prepended, and the dry run answered Hunk #1 succeeded at 3 (offset 2 lines). Found, but displaced.

If plain context fails, patch ignores edge lines of context, called fuzz; the default maximum fuzz factor is 2, and a larger factor increases the odds of a faulty patch.

ONE HONEST HOUR

Prepend two lines to a copy, dry-run your patch, and read the offset line verbatim.

Per this book's plan, the closing lesson teaches one friend diff in one sitting: run diff --version, read one 4c4 change, read one @@ -1,7 +1,7 @@ hunk, watch the exit status answer 1, and dry-run one small patch. Per the Wikipedia Diff article, the original utility was developed in the early 1970s at Bell Labs, was part of the 5th Edition of Unix released in 1974, and was written by Douglas McIlroy and James Hunt. This machine's captures, re-read from this book: diff (GNU diffutils) 3.10, 4c4, @@ -1,7 +1,7 @@, changed pair exit: 1, checking file h_copy.txt.

Comparison tools companion · No. 07
pass it on

Teaching diff

five lines, one sitting

five lines, one sitting1 version2 change3 hunk4 verdict5 dry rundiff (GNU diffutils) 3.104c4@@ -1,7 +1,7 @@changed pair exit: 1checking file h_copy.txtteach the readingsas much as the typing:they type every linepass it on: version, change, hunk, verdict, dry run, in one sitting

The whole book in one sitting with a friend: version, a change, a hunk, a verdict, a dry run. Five lines, one story: the smallest honest change set.

Teach the readings as much as the typing: what 2c2 says, what @@ -1,7 +1,7 @@ counts, why exit 1 is an answer, why the dry run comes first.

The lines they will meet are this book's own captures: diff (GNU diffutils) 3.10, 4c4, @@ -1,7 +1,7 @@, changed pair exit: 1, checking file h_copy.txt. Let them type every one.

ONE HONEST HOUR

Sit with one friend and teach diff in one sitting; they type the five lines, you read the ranges aloud.

Index

Index


c is for changed4
comm, three columns8
Ignored, not equal7
Offsets and fuzz9
Same or different6
Teaching diff10
The @@ header5