patchutils: The Sub-Second Toolkit for Manipulating Diffs Themselves

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.

Key Takeaway: patchutils treats unified diffs as data you can query, filter, split, merge, and re-diff — no repo, no VCS, no rebasing required.

All newsletters