You are hereGenerating and reading patch files

Generating and reading patch files


By thomas - Posted on 26 September 2007

We are working on a short piece of code, called count.c. I first copy count.c to a backup, count.c.orig and begin correcting count.c

patched code

#include <stdio.h>
#define LENGTH 100
#define HEIGHT 50
 
int main (int argc, char* argv[]) {
        int i;
        int j;
        int k;
        k=1;
        for (i=0; i<LENGTH; ++i)
                for (j=0; j<HEIGHT; ++j) {
                        k+=(i+j);
        }
        printf("k=%i\n",k);
}

original code
#include <stdio.h>
#define LENGTH 100
#define HEIGHT 50
 
int main (int argc, char* argv[]) {
        int i;
        int j;
        int k;
        for (i=0; i<LENGTH; ++i)
                for (j=0; j<HEIGHT; ++j) {
                        k+=(i+j);
        }
        printf("k=%i\n",k);
}

Generating the patch
In this very simple case we only have one line different in the files, to generate a patch file, we only need use diff -u

[thomas@host ~]$ diff -u count.c.orig count.c
--- count.c     2007-09-26 15:09:16.000000000 -0400
+++ count.c.orig        2007-09-26 15:09:24.000000000 -0400
@@ -6,7 +6,6 @@
        int i;
        int j;
        int k;
+      k=1;
        for (i=0; i<LENGTH; ++i)
                for (j=0; j<HEIGHT; ++j) {
                        k+=(i+j);

To store this in a patch file, we would use diff -u count.c count.c.orig >count.patch. Alternatively we could use the gendiff script provided by the rpm rpm. Gendiff is a nice little script that runs through a directory and makes a patch file for you based on the extension you gave to your original files.
[thomas@host ~]$ gendiff `pwd` .orig
--- /home/thomas/count.c.orig   2007-09-26 15:09:24.000000000 -0400
+++ /home/thomas/count.c        2007-09-26 15:18:55.000000000 -0400
@@ -6,6 +6,7 @@
        int i;
        int j;
        int k;
+       k=1;
        for (i=0; i<LENGTH; ++i)
                for (j=0; j<HEIGHT; ++j) {
                        k+=(i+j);

Gendiff is particularly nice when working with directories.

Applying the patch
To apply the patch we could rename count.c.orig to count.c and run patch.

[thomas@host ~]$ mv count.c.orig count.c
[thomas@host ~]$ patch <count.patch
patching file count.c
[thomas@host ~]$ cat count.c
#include <stdio.h>
#define LENGTH 100
#define HEIGHT 50
 
int main (int argc, char* argv[]) {
        int i;
        int j;
        int k;
        k=1;
        for (i=0; i<LENGTH; ++i)
                for (j=0; j<HEIGHT; ++j) {
                        k+=(i+j);
        }
        printf("k=%i\n",k);
}

This adds our line to the file or patches it.

Reading the patch file
The first two lines of the patch file indicate which two files are being compared. The line with --- is the old file, the +++ is the new file. At the end of the patch, the file will be the same as the +++ file. The dates after the name of the file are the last modification time of the file.

The next line indicates the context for the change, in our example @@ -6,6 +6,7 @@ is the context information for the "hunk" that is changing.
-6,6 means the original file starting at line 6 and continuing 6 lines.
+6,7 means the new file starting at line 6 and continuing 7 lines.

Next we need to know that each line that is unchanged between the two files is indented by a space, a line which is missing in the original file is prepended by a +, a line that is missing in the target file is prepended by a -.

Looking at our example we know that starting at line 6 we have 3 lines that are the same in both files, then we add another line to the target file at "+ k=1;" making our total in the target file 7.

In this simple example it's very easy to read the line numbers and make sense of them. Here is a more complex example.

--- libtool-1.4.2/ltmain.in~    Mon Feb  4 15:12:15 2002
+++ libtool-1.4.2/ltmain.in     Mon Feb  4 15:12:15 2002
@@ -745,6 +745,7 @@
     linker_flags=
     dllsearchpath=
     lib_search_path=`pwd`
+    inst_prefix_dir=
 
     avoid_version=no
     dlfiles=
@@ -875,6 +876,11 @@
          prev=
          continue
          ;;
+        inst_prefix)
+         inst_prefix_dir="$arg"
+         prev=
+         continue
+         ;;
        release)
          release="-$arg"
          prev=
@@ -976,6 +982,11 @@
        continue
        ;;
 
+      -inst-prefix-dir)
+       prev=inst_prefix
+       continue
+       ;;
+
       # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
       # so, if we see these flags be careful not to treat them like -L
       -L[A-Z][A-Z]*:*)
@@ -1851,7 +1862,16 @@
            if test "$hardcode_direct" = yes; then
              add="$libdir/$linklib"
            elif test "$hardcode_minus_L" = yes; then
-             add_dir="-L$libdir"
+             # Try looking first in the location we're being installed to.
+             add_dir=
+             if test -n "$inst_prefix_dir"; then
+               case "$libdir" in
+               [\\/]*)
+                 add_dir="-L$inst_prefix_dir$libdir"
+                 ;;
+               esac
+             fi
+             add_dir="-L$libdir $add_dir"
              add="-l$name"
            elif test "$hardcode_shlibpath_var" = yes; then
              case :$finalize_shlibpath: in
@@ -1861,7 +1881,16 @@
              add="-l$name"
            else
              # We cannot seem to hardcode it, guess we'll fake it.
-             add_dir="-L$libdir"
+             # Try looking first in the location we're being installed to.
+             add_dir=
+             if test -n "$inst_prefix_dir"; then
+               case "$libdir" in
+               [\\/]*)
+                 add_dir="-L$inst_prefix_dir$libdir"
+                 ;;
+               esac
+             fi
+             add_dir="-L$libdir $add_dir "
              add="-l$name"
            fi
 
@@ -3823,7 +3852,7 @@
        fi
       done
       # Quote the link command for shipping.
-      relink_command="(cd `pwd`; $SHELL $0 --mode=relink $libtool_args)"
+      relink_command="(cd `pwd`; $SHELL $0 --mode=relink $libtool_args @inst_prefix_dir@)"
       relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
 
       # Only create the output if not a dry run.
@@ -4124,12 +4153,30 @@
        dir="$dir$objdir"
 
        if test -n "$relink_command"; then
+         # Determine the prefix the user has applied to our future dir.
+         inst_prefix_dir=`$echo "$destdir" | sed "s%$libdir\$%%"`
+
+         # Don't allow the user to place us outside of our expected
+         # location b/c this prevents finding dependent libraries that
+         # are installed to the same prefix.
+         if test "$inst_prefix_dir" = "$destdir"; then
+           $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+           exit 1
+         fi
+
+         if test -n "$inst_prefix_dir"; then
+           # Stick the inst_prefix_dir data into the link command.
+           relink_command=`$echo "$relink_command" | sed "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+         else
+           relink_command=`$echo "$relink_command" | sed "s%@inst_prefix_dir@%%"`
+         fi
+
          $echo "$modename: warning: relinking \`$file'" 1>&2
          $show "$relink_command"
          if $run eval "$relink_command"; then :
          else
            $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
-           continue
+           exit 1
          fi
        fi

This is a patch from libtool, it's a bit old.
Starting at the first two lines we see that we are working with the file ltmain.in
The original file is ltmain.in~, the new one is ltmain.in

@@ -745,6 +745,7 @@

The next line should be read that starting at line 745 in the original with 6 lines of context we have the change at line 745 in the new file with 7 lines after patching. The patch then has 3 lines that are the same in both files, an addition and three more lines that are the same (3+1+3=7). Now, the key is that we are not done with these files, so the new file has one more line than the old file.

@@ -875,6 +876,11 @@
The next @@ lines say at line 875 in the original with 6 lines of context, but line 876 in the new file with 11 lines of context (3+5+3=11). We are at line 876 in the new file because the new file has one more line than the original file, and we have 11 lines of context because we have 5 new lines to add to the file.

@@ -976,6 +982,11 @@
Our next hunk makes this more clear, our original file reference starts at line 976, but the new file starts at line 982. 982 -976 = 6, which is 5 lines from hunk 2 and 1 line from hunk 1. Again, we are adding 5 lines so our context for the new file is 11 lines.

@@ -1851,7 +1862,16 @@
Now, in this hunk we have 10 additions and 1 deletion for a total of 9 new lines, so our context is 16 lines. You might think the context is 15 (3+9+3), but it is 16 because have to reference the context lines based on the file before we apply our hunk. Our new file is starting at line 1862 because we are now 11 lines longer in the new file.

@@ -1861,7 +1881,16 @@
Adding up all our changes we see that we added 9 lines in hunk 4, 5 lines in hunk 3, 5 lines in hunk 2 and 1 line in hunk 1 for a total of 20 (1881-1861=20). We have 10 lines of changes so our context is 16 lines.

That should be about all you need to know to read patch files in unified format. For more information try the wikipedia diff page.

Tags

thanks a lot. very clear and well explained with good examples.
cheers ...

Hi,

Thank you very much for your clear explanation.

But I have a quick question:
Why it's 7 lines hunk in the old file at 1851? Isn't it 6 lines in the old file?

All of the other parts are extremely clear! :-)

Thank you so much!

The deleted line from the original file counts as context, so there are 6 lines that are unchanged + 1 line deleted for 7 lines in the original file. There are 10 lines added to the new file with the 6 lines of context for 16 lines total in the update.

Hope that clears it up...

Thanks very much. Very nice and clear article.

Great explanation. That was extremely useful and helpful. Thanks.

Thanks a lot. If I saw this extermely simple explanation before, I didn't have to waste many hours to read patch file and modify the code manually. I appreciate it.

Good Luck

Thanks a lot, that was very useful for me! I didn't understand how to read the context line before, and so when I tried to edit a patchfile by hand I got the patch utility confused...

Post new comment

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <bash>, </bash>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <latex>, </latex>, <sql>, </sql>, <php>, <python>, <ruby>. The supported tag styles are: <foo>, [foo].

More information about formatting options

Type the characters you see in this picture.
Type the characters you see in the picture; if you can't read them, submit the form and a new image will be generated. Not case sensitive.  Switch to audio verification.