Module 10 · Putting it all together
diff and patch
See exactly what changed between two files or directories with diff, save the change as a patch, and apply or undo it with patch.
What you will learn
- Read a unified diff: headers, hunks, `-` and `+` lines.
- Compare files and directories with `diff -u`, `-q` and `-r`, and use its exit status.
- Create a patch file and apply or reverse it with `patch`.
Before you change a configuration file, copy it: cp app.conf app.conf.orig. After the change, diff tells you precisely what you did, line by line. That output is not just for reading. Saved to a file it becomes a patch, a recipe that patch can replay on another copy of the original, on another machine, or undo later. This is how changes to source code travelled by email for decades, and it is still how git shows you changes.
~% cd lab/l95
l95% cat old/app.conf
host=localhost
port=8080
debug=yes
l95% diff -u old/app.conf new/app.conf
--- old/app.conf
+++ new/app.conf
@@ -1,3 +1,3 @@
host=localhost
-port=8080
-debug=yes
+port=9090
+debug=no
l95% echo $?
1
Reading a unified diff
The --- line names the old file and +++ the new one. Each block starting with @@ is a hunk: -1,3 +1,3 means "lines 1 to 3 of the old file become lines 1 to 3 of the new one". Inside a hunk, lines starting with a space are unchanged context, - lines were removed and + lines were added. A changed line therefore shows up as a - followed by a +. The context lines are what lets patch find the right spot even if the file has moved a little.
Other systems print an older "normal" format by default and need -u for this one. BusyBox diff only knows the unified format, so here diff and diff -u print the same thing; write -u anyway, it is the habit that works everywhere. The exit status is useful in scripts: 0 means identical, 1 means different and 2 means trouble, such as a missing file.
| Option | Meaning |
|---|---|
-u | Unified format (the only one in BusyBox) |
-q | Only say whether the files differ |
-r | Recurse into directories |
-N | Treat missing files as empty (shows new files in full) |
-i / -w / -B | Ignore case / all whitespace / blank lines |
l95% diff -rq site site.bak
Files site/index.html and site.bak/index.html differ
Only in site: new.html
Making and applying a patch
l95% diff -u old/app.conf new/app.conf > app.patch
l95% cp old/app.conf live.conf
l95% patch live.conf app.patch
patching file live.conf
l95% cat live.conf
host=localhost
port=9090
debug=no
l95% patch -R live.conf app.patch
patching file live.conf
patch FILE PATCHFILE (or patch FILE < PATCHFILE) applies the recipe to FILE. -R reverses it, turning + into -, which is your undo button. Without a FILE argument patch reads the file names from the ---/+++ headers, and -p1 strips the first directory from them, the usual way to apply a patch for a whole project from its top directory: patch -p1 < fix.patch. Without an explicit FILE, BusyBox patches the file named on the +++ line, so name the target when in doubt.
Commands in this lesson
| Command | What it does |
|---|---|
diff -u old new | Show changes in unified format. |
diff -q a b | Only report whether they differ. |
diff -rq dir1 dir2 | Compare two directory trees briefly. |
diff -u old new > fix.patch | Save the change as a patch. |
patch file fix.patch | Apply a patch to a file. |
patch -R file fix.patch | Undo (reverse) a patch. |
patch -p1 < fix.patch | Apply a project patch from its top directory. |
Quiz
In a unified diff, what does a line starting with `+` mean?
- It exists only in the new file (added).
- It is unchanged context.
- It was removed.
`diff a b` exits with status 1. What does that mean?
- An error occurred.
- The files differ.
- The files are identical.
How do you undo a patch you just applied to `app.conf`?
- `patch -R app.conf fix.patch`
- `diff -R app.conf`
- It cannot be undone.
You only want to know which files differ between two directories, not the details. Which command?
- `diff -u dir1 dir2`
- `diff -rq dir1 dir2`
- `patch -r dir1 dir2`
What is the job of the context lines (starting with a space) in a patch?
- They are comments for humans only.
- They help `patch` find the right place to apply the change.
- They are deleted by `patch`.
Practice
Save the unified diff between `/root/lab/l95/old/app.conf` (first) and `/root/lab/l95/new/app.conf` (second) into `/root/lab/l95/app.patch`.
Apply the patch `/root/lab/l95/fix.patch` to `/root/lab/l95/live.conf`, so that it ends up with `port=9090` and `debug=no`.
Compare the directories `/root/lab/l95/site` and `/root/lab/l95/site.bak` recursively and save only the brief report (which files differ, which exist in only one) into `/root/lab/l95/report.txt`.
Open this lesson in the app to do the tasks in a real Linux machine and have them checked.