Text processing
patch
Apply a diff to files, turning the original versions into the changed ones.
patch [OPTION...] [ORIGFILE [PATCHFILE]]
patch is the other half of diff: it reads a diff (usually unified, from diff -u or
git diff) and makes those edits to your files. It reads the patch from standard input unless
you give -i FILE, and it finds the files to change from the ---/+++ header lines.
It does not need the file to be exactly as it was. Each hunk carries a few lines of context,
and patch looks for them near the stated line number: a hunk that moved is applied with an
offset, one whose context changed slightly with fuzz, and one that cannot be placed is
rejected into a .rej file while the rest still applies.
The option you will need most is -pN, which strips N leading directories from the paths in
the headers. Patches made by git name files a/src/main.c and b/src/main.c, so you apply
them from the top of the tree with -p1. Always try --dry-run first on anything that
matters. The exit status is 0 when everything applied, 1 when some hunks failed, 2 on serious
trouble.
Examples
Apply a patch to one file
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
patch < todo.patch
cat todo.txt
patching file todo.txt buy milk fix login bug write integration tests fix logout bug deploy v2.4
patch reads the unified diff from stdin, takes the file name from the ---/+++ header,
and edits todo.txt in place: the - line is removed and the + line added. It prints
the name of each file it patches.
Check a patch before applying it
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
patch --dry-run < todo.patch
cat todo.txt
checking file todo.txt buy milk fix login bug write tests fix logout bug deploy v2.4
--dry-run reports what would happen and changes nothing, as cat confirms. Use it to
catch failed hunks before half a patch lands.
Strip path prefixes with -p1
--- a/src/main.c
+++ b/src/main.c
@@ -3,4 +3,4 @@
int main(void) {
- printf("hello, world\n");
+ printf("hello, demo\n");
return 0;
}
patch -p1 < fix.patch
grep printf src/main.c
patching file src/main.c
printf("hello, demo\n"); The headers name a/src/main.c and b/src/main.c, the convention git uses. -p1 strips
the first path component, so patch edits src/main.c relative to the current directory.
Without it, patch would look for a directory called a.
Name the patch file and the target explicitly
--- greet.sh
+++ greet.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-echo "Hello, ${1:-world}!"
+echo "Hi there, ${1:-world}."
patch scripts/greet.sh -i greeting.patch
scripts/greet.sh
patching file scripts/greet.sh Hi there, world.
Naming the file to patch overrides the names in the header, and -i reads the patch from
a file instead of stdin. Here the header says greet.sh but the file lives in scripts/.
Naming the target also avoids surprises when the --- and +++ names differ and both
files exist: patch then picks by its own rules (fewest path components first), which may
not be the file you meant.
Keep a backup of the original
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
patch -b < todo.patch
diff todo.txt.orig todo.txt
patching file todo.txt 3c3 < write tests --- > write integration tests
-b saves each original file with a .orig suffix before changing it. The final diff
shows the change and exits with 1 because the files differ.
Undo a patch with -R
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
patch < todo.patch
patch -R < todo.patch
sed -n 3p todo.txt
patching file todo.txt patching file todo.txt write tests
-R applies the patch backwards, turning + lines into removals and - lines into
additions. Line 3 is back to its original text.
Skip a patch that is already applied with -N
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
patch < todo.patch
patch -N < todo.patch
patching file todo.txt patching file todo.txt Reversed (or previously applied) patch detected! Skipping patch. 1 out of 1 hunk ignored -- saving rejects to file todo.txt.rej
Applied a second time, the hunk looks reversed. Without -N, patch stops to ask whether
to undo it instead. -N answers no without asking: the hunk is skipped, saved to
todo.txt.rej, and the exit status is 1, so a script can tell it did nothing.
A hunk that moved still applies
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
sed -i '1i book flights\nrenew passport' todo.txt
patch < todo.patch
patching file todo.txt Hunk #1 succeeded at 3 (offset 2 lines).
Two lines were inserted at the top after the patch was made, so the hunk's context is now two lines further down. patch finds it anyway and reports the offset.
A hunk that does not fit is rejected
--- todo.txt
+++ todo.txt
@@ -1,5 +1,5 @@
buy milk
fix login bug
-write tests
+write integration tests
fix logout bug
deploy v2.4
sed -i 's/write tests/write unit tests/' todo.txt
patch < todo.patch
echo "exit status: $?"
cat todo.txt.rej
patching file todo.txt Hunk #1 FAILED at 1. 1 out of 1 hunk FAILED -- saving rejects to file todo.txt.rej exit status: 1 --- todo.txt +++ todo.txt @@ -1,5 +1,5 @@ buy milk fix login bug -write tests +write integration tests fix logout bug deploy v2.4
The line the patch wants to remove no longer exists, so the hunk fails. patch writes it to
todo.txt.rej, leaves the file unchanged and exits with 1. Resolve rejects by hand, then
delete the .rej file.
Apply a patch to a whole tree
Setup run before this example
cp -r src /tmp/src.orig
sed -i 's/hello, world/hello, demo/' src/main.c
printf 'print("new")\n' > src/new.py
cd /home/dev/demo && diff -ruN /tmp/src.orig src | sed 's|/tmp/src.orig|a/src|; s|^+++ src|+++ b/src|' > /tmp/tree.patch
rm -r src && cp -r /tmp/src.orig srcpatch -p1 < /tmp/tree.patch
cat src/new.py
patching file src/main.c
patching file src/new.py
print("new") A recursive diff -ruN produces one patch for many files, including new ones. patch
applies each section in turn and creates src/new.py from nothing.
Common pitfalls
Wrong
-plevel is the classic failure: patch asks "File to patch:" or reports the file missing. Look at the+++header and count how many leading directories to strip from where you stand.Patches with CRLF line endings, or files with them, make every hunk fail. Use
--binaryon both sides consistently, or convert line endings first.A partly applied patch leaves
.rejand possibly.origfiles lying around. Run with--dry-runfirst, and clean up withfind . -name '*.rej' -o -name '*.orig'after.Patches copied from a web page or email often lose trailing whitespace on context lines and fail to apply. Use the raw file, or
-lto ignore whitespace differences.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
macOS and the BSDs ship a BSD patch;
-p,-R,-N,-i,-band--dry-run(BSD also spells it-C/--check) behave the same for everyday use.
Options worth knowing
A selection, described in our own words. For the full list, see patch(1) or patch --help.
| Option | What it does |
|---|---|
-p, --strip NUM | Strip NUM leading path components from file names in the patch. |
-i, --input PATCHFILE | Read the patch from PATCHFILE instead of stdin. |
-R, --reverse | Apply the patch in reverse, undoing it. |
-N, --forward | Ignore patches that seem reversed or already applied. |
--dry-run | Print what would happen without changing any files. |
-b, --backup | Save each original file with a .orig suffix. |
-d, --directory DIR | Change to DIR before doing anything. |
-o, --output FILE | Write the patched result to FILE instead of in place. |
-r, --reject-file FILE | Write rejected hunks to FILE. |
-F, --fuzz NUM | Allow up to NUM lines of mismatched context. |
-l, --ignore-whitespace | Ignore whitespace differences when matching context. |
-s, --silent | Work silently unless an error occurs. |
-t, --batch | Never ask questions; skip patches whose files are missing. |
-f, --force | Never ask questions and assume the patch is not reversed. |
-E, --remove-empty-files | Remove files that are empty after patching. |
Related
diffCompare two files or directories line by line and print the changes that turn one into the other.cmpCompare two files byte by byte and report the first difference, or just whether they differ.sedEdit a stream of text with a script of commands, most often to substitute text or delete lines.- RedirectionHow >, >>, 2>, 2>&1, &>, < and exec move a command's input and output between files and file descriptors, and why the order matters.