diff and patch Basics - Getting and Applying Diffs
What You Will Learn
- How to compare two files with
diffand read the output - How to interpret unified diff format (
diff -u) - How to apply a patch file with
patch - How to revert a patch with
patch -R
Quick Summary
- View diff:
diff -u old_file new_file - Save patch:
diff -u old_file new_file > changes.patch - Apply patch:
patch -p0 < changes.patch - Revert patch:
patch -R -p0 < changes.patch
Prerequisites
- OS: Ubuntu or any Linux distribution
diffandpatchare installed by default on most Linux systems
What Is diff?
diff compares two files line by line and outputs what changed between them. It is used daily to review changes in source code, compare configuration files against backups, and generate patch files for distribution.
How to Use diff
Basic Comparison
$ diff old.txt new.txt
If there are no differences, nothing is printed. With differences, the default "normal" format output looks like this:
2c2 < old content --- > new content
The normal format is hard to read and not suitable for patch. Use the unified format instead.
Unified Format (-u)
The -u option produces unified format output — the standard format for patch files.
$ diff -u old.txt new.txt
Example output:
--- old.txt 2026-06-01 10:00:00.000000000 +0000
+++ new.txt 2026-06-01 10:05:00.000000000 +0000
@@ -1,5 +1,5 @@
line1 (unchanged)
-old line2
+new line2
line3 (unchanged)
How to read it:
| Symbol | Meaning |
|---|---|
--- |
Original (before) file |
+++ |
Modified (after) file |
@@ |
Hunk header with line numbers |
- |
Removed line |
+ |
Added line |
(space) |
Context line (unchanged) |
The hunk header @@ -1,5 +1,5 @@ means: starting at line 1, showing 5 lines from the old file / 5 lines from the new file. Three context lines before and after each change are included by default.
Recursive Directory Comparison (-r)
Use -r with -u to compare entire directory trees:
$ diff -ur dir_old/ dir_new/
Each changed file appears as a separate unified diff block in the output.
Useful diff Options
| Option | Description |
|---|---|
-u |
Unified format (required for patch) |
-r |
Recursive (compare directories) |
-i |
Ignore case differences |
-w |
Ignore all whitespace |
-b |
Ignore changes in whitespace amount |
--color |
Colorize output (GNU diff) |
Saving the Diff to a Patch File
Redirect the diff output to a file:
# Single file $ diff -u original.txt modified.txt > changes.patch # Entire directory $ diff -ur dir_old/ dir_new/ > project.patch
This file is what you pass to patch when applying changes.
What Is patch?
patch takes a diff file produced by diff and applies those changes to a target file or directory. It is how bug fixes and security patches are distributed in open-source software: the maintainer runs diff, ships the .patch file, and users run patch to apply it.
How to Use patch
Understanding the -p Strip Level
The -p option controls how many leading path components to strip from filenames inside the patch header.
--- a/src/config.txt ← with -p1, interpreted as "src/config.txt"
+++ b/src/config.txt
| Option | Behavior |
|---|---|
-p0 |
Use the full path as-is |
-p1 |
Strip one leading component (removes a/ or b/) |
Git-generated patches always include a/ and b/ prefixes, so -p1 is the most common choice for Git patches. For patches created with plain diff -u (no prefix), use -p0.
Dry Run First
Always preview before applying:
$ patch --dry-run -p0 < changes.patch
--dry-run checks whether the patch applies cleanly without modifying any files. If it reports no errors, proceed with the real apply.
Applying a Patch
For patches created with diff -u (plain, no a//b/ prefix):
$ patch -p0 < changes.patch
For Git-generated patches or patches with a//b/ prefixes:
$ patch -p1 < project.patch
If patch reports "Hunk FAILED", the patch does not match the current state of the target file — the file may have already been patched, or was modified independently. Use --dry-run to diagnose before attempting.
Rejecting Hunks
When a hunk fails, patch writes the rejected portions to a .rej file (e.g., config.txt.rej). Inspect it to apply the changes manually.
Reverting a Patch
The -R flag reverses a patch — applying it undoes the original change:
$ patch -R -p0 < changes.patch # Git-format patch $ patch -R -p1 < project.patch
Reverting requires that the context lines in the patch still match the target file. If the file has been changed further since the patch was applied, reverting may fail or produce incorrect results.
Practical Workflows
Sharing a Config File Change
# 1. Save the original $ cp nginx.conf nginx.conf.orig # 2. Edit the file $ vim nginx.conf # 3. Generate the patch $ diff -u nginx.conf.orig nginx.conf > nginx-fix.patch # 4. Recipient applies the patch $ patch --dry-run -p0 < nginx-fix.patch $ patch -p0 < nginx-fix.patch
Applying an Open-Source Patch
# Run from the project root directory $ patch --dry-run -p1 < bugfix.patch $ patch -p1 < bugfix.patch # Undo if something goes wrong $ patch -R -p1 < bugfix.patch
Generating a Git-Compatible Patch
When working in a Git repository, git diff produces output that patch -p1 can consume directly:
$ git diff > my-changes.patch $ patch -p1 < my-changes.patch
For committed changes, git format-patch is more appropriate as it preserves commit metadata.
Summary
| Command | Purpose |
|---|---|
diff -u old new |
Show unified diff |
diff -ur dir1/ dir2/ |
Compare directories recursively |
diff -u old new > fix.patch |
Generate a patch file |
patch --dry-run -p0 < fix.patch |
Preview patch application |
patch -p0 < fix.patch |
Apply patch (plain format) |
patch -p1 < fix.patch |
Apply patch (Git format) |
patch -R -p0 < fix.patch |
Revert a patch |
Copy-Paste Templates
# Generate patch diff -u original.txt modified.txt > changes.patch # Preview patch --dry-run -p0 < changes.patch # Apply patch -p0 < changes.patch # Revert patch -R -p0 < changes.patch