patch Command Explained

patch Command Explained

patch is the other half of diff. Where diff describes what changed between two files, patch takes that description and actually applies it to a real file, which is what makes the pair genuinely useful together rather than just informative.

Basic usage

diff -u original.conf modified.conf > changes.patch
patch original.conf < changes.patch

Given a unified diff (generated with diff -u) and the original file, patch transforms the original into exactly what the modified version looked like, applying every addition and removal the diff describes.

diff original.conf modified.conf
# 3c3
# < max_connections = 100
# ---
# > max_connections = 250

cat original.conf
# max_connections = 100

patch original.conf < changes.patch
cat original.conf
# max_connections = 250

Applying a patch without specifying the target explicitly

patch < changes.patch

Many patch files include the target filename directly inside their header (the --- and +++ lines from diff -u’s output), which means patch can often figure out which file to modify on its own, without you needing to name it explicitly, as long as you are running the command from the correct directory relative to those recorded paths.

Reversing a patch

patch -R < changes.patch

-R (reverse) applies the same diff backward, undoing a change that was previously applied. This works because a unified diff fully describes both states, what was removed and what was added, so swapping which side is treated as the starting point and which is the target cleanly reverses the operation.

# Apply, verify, and undo, as a safe workflow for testing a change
patch original.conf < changes.patch
# ... review the result ...
patch -R original.conf < changes.patch
# back to the original state

The -p flag: stripping leading path segments

# A patch generated from within a git repository often looks like:
--- a/src/config.c
+++ b/src/config.c

patch -p1 < changes.patch

Patches generated from source control systems like Git commonly include leading path prefixes (a/ and b/ by convention) that do not correspond to real directories on disk; they are just labels distinguishing the “before” and “after” versions. -p1 tells patch to strip exactly one leading path segment from each file path in the patch before looking for the actual file, so a/src/config.c becomes src/config.c, matching the real relative path from wherever you are running the command.

patch -p0 < changes.patch    # strip no path segments (use the path exactly as given)
patch -p1 < changes.patch     # strip one segment (the common case for git-generated patches)
patch -p2 < changes.patch      # strip two segments

Getting this number wrong is one of the most common reasons a patch fails to find its target file at all, reporting that the file it expected does not exist.

When a patch does not apply cleanly

patch original.conf < changes.patch
# patch: **** malformed patch at line 12
# 1 out of 1 hunk FAILED -- saving rejects to file original.conf.rej

If the target file has drifted from the state the patch expects, for example if it was independently edited after the patch was generated, patch may fail to apply some or all of the change. It reports which “hunks” (individual chunks of change) failed, and saves the portions it could not apply into a .rej (reject) file, while still applying whatever parts succeeded cleanly. Reviewing the .rej file and manually reconciling that specific portion is the standard way to resolve a partial failure like this.

Previewing a patch without applying it

patch --dry-run < changes.patch
# checking file original.conf
# Hunk #1 succeeded at 3.

--dry-run reports exactly what would happen, success or failure, for every hunk in the patch, without making any actual modification to the target file. This is a sensible safety check before applying a patch to a file that would be inconvenient to restore if something went wrong.

A complete real-world workflow

# 1. Someone shares a fix as a patch file
cat fix.patch

# 2. Preview it first
patch --dry-run -p1 < fix.patch

# 3. Apply it for real
patch -p1 < fix.patch

# 4. If something looks wrong, reverse it
patch -R -p1 < fix.patch

This pattern, generated by diff -u, previewed with --dry-run, applied with patch, and reversible with -R if needed, is exactly how software patches and configuration fixes have been distributed and applied on Unix-like systems for decades, well before modern version control tools existed, and it still shows up regularly in bug reports, mailing lists, and quick one-off fixes today.

Frequently Asked Questions

What does the patch command do?

patch takes a diff file, generated by the diff command, and applies the changes it describes to a real, actual file on disk, transforming it from its original state into the modified state the diff represents. It is the receiving half of a pair of tools: diff describes a change, patch applies it.

How do I apply a patch file to a set of source files?

Run patch < changes.patch from within the directory the patch expects, or specify the target file explicitly with patch original.conf < changes.patch. patch reads the diff file, figures out which file or files it applies to (based on information stored in the patch file itself), and modifies them accordingly.

How do I undo a patch that has already been applied?

Add the -R flag (reverse), such as patch -R < changes.patch, which applies the exact same diff in reverse, restoring the file to its original pre-patch state. This works because a unified diff fully describes both directions of the change, added lines and removed lines, so reversing which side is treated as the source and which is the target undoes it cleanly.

What does the -p flag do when applying a patch?

Patches generated from within a project directory often include leading path segments in the file paths they reference, such as a/src/config.c and b/src/config.c in patches generated by git. The -p flag tells patch how many leading path segments to strip before looking for the actual file, so patch -p1 strips one segment, turning a/src/config.c into src/config.c, matching how the file actually sits relative to your current directory.

What happens if a patch does not apply cleanly?

If the target file has changed since the patch was generated, in a way that conflicts with what the patch expects to find, patch will report a “failed hunk” for that specific section and typically create a .rej (reject) file containing the portion that could not be applied automatically, while still applying whatever parts of the patch did succeed. Reviewing the .rej file and manually applying that specific portion is the standard way to resolve this.

Can I preview what a patch would do without actually applying it?

Yes, use the —dry-run flag, such as patch —dry-run < changes.patch, which reports whether the patch would apply successfully and shows what it would do, without making any actual changes to the target files. This is a useful safety check before committing to an actual patch application, especially on files you cannot easily revert.