How to Use Patch and Diff Commands to Create and Apply Patches
The world of Unix is a place where everything is done the right way, till there is an even “righter” way to do it. For everything that gets coded, there is always something left to be edited. Almost every project in the Linux (or other unix related OS) community is based on patches. There are even quite a lot of patches for the linux kernel itself.
A patch is essentially a remedy of some kind to the original source code (or just data). Imagine, for instance, that you just discovered a critical security bug in openssh (well, you won’t be the first or the last to do that). After you fix that, you would want to inform the others (hopefully) about this bug and provide your solution. While you could still just provide the authors with your version of openssh sources, wouldn’t it be better if you just provided them with a patch, that when applied, it will automatically do the necessary changes to the needed files ?
This is where the great diff and patch commands can help. Diff is actually a command that compares two or more files line by line and provides a report indicating what is different between them. Let’s examine how diff works by examples :
How Diff Works
In order to better understand how diff works, it would be a good idea to create two files to diff one against the other. Let’s say that the names of the two files are “original.txt” and “changed.txt”. As you can understand, the original one corresponds to the original version of a file and the changed one is the one that you supposedly created after some editing you did on the original.
The contents of “original.txt”:
example of diff
and example of patch
The contents of “changed.txt”:
example of diff patched
and example of patch
new line added
So, what we first need to do is locate the differences of the two files. This is what happens now :
nemesys:Desktop hthought$ diff -u original.txt changed.txt --- original.txt 2009-12-02 22:52:53.000000000 -0500 +++ changed.txt 2009-12-02 22:53:15.000000000 -0500 @@ -1,2 +1,3 @@ -example of diff -and example of patch \ No newline at end of file +example of diff patched +and example of patch +new line added \ No newline at end of file
You first notice the names of the files that we compare, along with their last modification dates. The “@@ -1,2 +1,3 @@” specifies that starting from line 1 of “original.txt”, there is a chunk of two lines of data and starting from line 1 of “changed.txt”, there is a chunk of three lines of data. After that, you can start seeing the actual contents of the two files. If there is a line that is exactly the same in both files, it gets no sign (not a – or +), meaning that it is the same. If not, it prints both versions so that you see the differences between them and understand which file they refer to.
Now, while this is good, it doesn’t really do much for us as it is. What we would want to do is redirect this output to a file as a patch for “original.txt”. Then, when we want to change that file, we would just apply the patch to transform “original.txt” to “changed.txt”. The first command to do to achieve that is :
nemesys:Desktop hthought$ diff -u original.txt changed.txt > original.patch
Applying The Patch
Applying the patch is pretty easy. We just use the patch command to do this like (from our working directory):
patch original.txt < original.patch
This is really easy but most times this is not the common case. In 90% of the cases, a patch applies to more than one files and directories. And now comes the “a bit tricky” p directive. To better understand what this actually specifies, imagine that you want to apply a patch to a a list of files under the directory “dir1″. Then, this “dir1″ directory contains another “dir2″ directory that the patch has to patch as well. The person that created the patch did that under his/her own path names. Therefore, if your working directory is on “dir2″, the patch will not be able to recognize that it has to start to patch from the previous directory. Thus, the general rule is to apply the patch to your top level directory. When you are at that one, a p1 switch is just ok. If you were in “dir2″, for instance, a p2 would be needed. Thus, in “dir1″, you would apply the patch like :
patch -p1 < original.patch
and remove it with :
patch -p1 -R < original.patch
Create a Whole Directory Patch
As you would expect, the first thing is to create a local backup of the whole directory that includes the files that are about to be edited. Then, after you finish with your changes, you just make a recursive patch using :
diff -urN originalDir/ changedDir/ > fullDir.patch
And you just apply it to the whole directory as shown above, simply by making it your working directory and specifying -p1 as the p parameter.