Using diff and patch

Problem

You can never remember how to use diff to create patches that may later be applied using patch.

Solution

If you are creating a simple patch for a single file, use:

$ diff -u original_file modified_file > your_patch

If you are creating a patch for multiple files in parallel directory structures, use:

$ cp -pR original_dirs/ modified_dirs/

# Make changes here

$ diff -Nru original_dirs/ modified_dirs/ > your_comprehensive_patch

To be especially careful, force diff to treat all files as ASCII using -a, and set your language and timezone to the universal defaults as shown:

$ LC_ALL=C TZ=UTC diff -aNru original_dirs/ modified_dirs/ > your_comprehensive_patch

$ LC_ALL=C TZ=UTC diff -aNru original_dirs/ modified_dirs/
diff -aNru original_dirs/changed_file modified_dirs/changed_file
--- original_dirs/changed_file 2006-11-23 01:04:07.000000000 +0000
+++ modified_dirs/changed_file 2006-11-23 01:04:35.000000000 +0000
@@ -1,2 +1,2 @@
 This file is common to both dirs.
-But it changes from one to the other.
+But it changes from 1 to the other.
diff -aNru original_dirs/only_in_mods modified_dirs/only_in_mods
--- original_dirs/only_in_mods 1970-01-01 00:00:00.000000000 +0000
+++ modified_dirs/only_in_mods 2006-11-23 01:05:58.000000000 +0000
@@ -0,0 +1,2 @@
+While this file is only in the modified dirs.
+It also has two lines, this is the last.
diff -aNru original_dirs/only_in_orig modified_dirs/only_in_orig
--- original_dirs/only_in_orig 2006-11-23 01:05:18.000000000 +0000
+++ modified_dirs/only_in_orig 1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-This file is only in the original dirs.
-It has two lines, this is the last.

To apply a patch file, cd to the directory of the single file, or to the parent of the directory tree and use the patch command:

cd /path/to/files
patch -Np1 < your_patch

The -N argument to patch prevents it from reversing patches or re-applying patches that have already been made. -p number removes number of leading directories to allow for differences in directory structure between whoever created the patch and whoever is applying it. Using -p1 will often work; if not, experiment with -p0, then -p2, etc. It’ll either work or complain and ask you what to do, in which case you cancel and try something else unless you really know what you are doing.

Discussion

diff can produce output in various forms, some of which are more useful than others. Unified output, using -u, is generally considered the best because it is both reasonably human-readable yet very robust when used with patch. It provides three lines of context around the change, which allows a human reader to get oriented and allows the patch command to work correctly even if the file to be patched is different than the one used to create the patch. As long as the context lines are intact, patch can usually figure it out. Context output, using -c, is similar to -u output, but is more redundant and not quite as easy to read. The ed format, using -e, produces a script suitable for use with the ancient ed editor. Finally, the default output is similar to the ed output, with a little more human-readable context.

# Unified format (preferred)$ diff -u original_file modified_file
--- original_file       2006-11-22 19:29:07.000000000 -0500
+++ modified_file       2006-11-22 19:29:47.000000000 -0500
@@ -1,9 +1,9 @@
-This is original_file, and this line is different.
+This is modified_file, and this line is different.
This line is the same.
So is this one.
And this one.
Ditto.
-But this one is different.
+But this 1 is different.
However, not this line.
And this is the last same, same, same.


# Context format
$ diff -c original_file modified_file
*** original_file       Wed Nov 22 19:29:07 2006
--- modified_file       Wed Nov 22 19:29:47 2006
***************
*** 1,9 ****
! This is original_file, and this line is different.
  This line is the same.
  So is this one.
  And this one.
  Ditto.
! But this one is different.
  However, not this line.
  And this is the last same, same, same.

--- 1,9 ---
! This is modified_file, and this line is different.
  This line is the same.
  So is this one.
  And this one.
  Ditto.
! But this 1 is different.
  However,
# 'ed' format
$ diff -e original_file modified_file
6c
But this 1 is different.
.
1c
This is modified_file, and this line is different.
.


# Normal format
$ diff original_file modified_file
1c1
< This is original_file, and this line is different.
> This is modified_file, and this line is different.
6c6
< But this one is different.
> But this 1 is different.

The -r and -N arguments to diff are simple yet powerful. -r means, as usual, recursive operation though the directory structure, while -N causes diff to pretend that any file found in one directory structure also exists in the other as an empty file. In theory, that has the effect of creating or removing files as needed; however, in practice -N is not supported on all systems (notably Solaris) and it may end up leaving zerobyte files lying around on others. Some versions of patch default to using -b, which leaves lots of .orig files laying around, and some versions (notably Linux) are less chatty than others (notably BSD). Many versions (not Solaris) of diff also support the -p argument, which tries to show which C function the patch affects.

Resist the urge to do something like diff -u prog.c.orig prog.c. This has the potential to cause all kinds of confusion since patch may also create .orig files. Also resist the urge to do something like diff -u prog/prog.c new/prog/prog.c since patch will get very confused about the unequal number of directory names in the paths.

See Also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.185.194