2026-07-13
Everyone learned diff and patch. Almost nobody learned that Tim Waugh shipped a whole family of tools in 1998 for slicing, dicing, and re-comparing patches as data. patchutils gives you interdiff, filterdiff, combinediff, splitdiff, grepdiff, and rediff. If you've ever hand-edited a .patch and watched patch reject three hunks because you miscounted context lines, this package will feel like a cheat code.
Install: apt install patchutils / brew install patchutils / dnf install patchutils.
interdiff — the killer app. You reviewed feature-v1.patch yesterday. Today the author sends feature-v2.patch. What actually changed? Not "run diff on two patches" — that gives you gibberish with @@ markers as content. interdiff reconstructs both trees mentally and emits the true delta:
$ interdiff feature-v1.patch feature-v2.patch
--- a/src/parser.c
+++ b/src/parser.c
@@ -42,7 +42,7 @@
- if (n < 0) return -1;
+ if (n <= 0) return -1;
That's what git calls range-diff — except interdiff works on any two unified patches from anywhere: mailing lists, review tools, git format-patch output, a tarball from 2004. No repo required.
filterdiff — surgical extraction. A vendor drops a 40-file patch on you and you only trust the changes under drivers/. Pull just those hunks:
$ filterdiff -i 'drivers/*' vendor.patch > drivers-only.patch
$ filterdiff -x '*/tests/*' -x '*.po' vendor.patch > no-tests-no-translations.patch
$ filterdiff --hunks=1,3 -i src/foo.c vendor.patch # specific hunks
$ filterdiff --lines=5- vendor.patch # drop hunks < 5 lines
grepdiff — find the file and the hunk. Regular grep on a patch tells you the string exists somewhere. grepdiff tells you which hunk touches lines matching your pattern, and can print only those hunks:
$ grepdiff 'kmalloc' --output-matching=hunk 6.9-to-6.10.patch | wc -l
$ grepdiff -E 'CVE-\d{4}' --output-matching=file security.patch
splitdiff / combinediff — reshape patch series. Turn one monster patch into per-file patches, then recombine what you want:
$ splitdiff -a -d monster.patch # writes monster.patch.001, .002, ...
$ combinediff a.patch b.patch > merged.patch
rediff — the one that saves your afternoon. You hand-edited a patch to remove a hunk or fix a typo, and now the line numbers in the @@ -x,y +a,b @@ headers are wrong. patch will fuzz-match some hunks and reject others. rediff re-computes the headers against the original tree:
$ rediff broken.patch > fixed.patch
# Reads each hunk, finds the true offset in the source, rewrites the header.
Why not just git? Because half the diffs in your life aren't in a repo: kernel patches on LKML, distro SPECS patches, dpkg-source quilt series, security advisories, code review email attachments, patches embedded in HTML bug reports (dehtmldiff handles that too). patchutils treats a unified diff as a first-class data structure independent of any VCS, which is exactly what it is.
Combine with lsdiff (list files touched by a patch) and you have a full IDE for patch archaeology in ~200KB of C.
