作为程序员,了解diff
和patch
命令是非常必要的。比如说发现某个项目有bug,而自己又没有提交权限,此时最合适的解决方法就是用diff
命令做一个补丁发给组长。组长看到补丁后会立刻明白你的意图。
有人说直接传一个工程不就完了?不要忘了,补丁文件尺寸更小传输更快,而且可以明显看到都做了哪些修改。就算你把修改后的工程传过去,组长还需要用对比工具查看做了哪些修改,这样费时费力。
下面开始做实验。
创建实验目录和文件
创建一个实验目录demo
mkdir demo
进入demo
cd demo
模拟一个项目目录src
mkdir -p src/a/b/c/d
创建一个文件
vim src/a/b/c/d/file
内容是
line1
line2
line3
假设我们发现项目src
需要修改,那么拷贝src
并命名为src_new
cp -r src src_new
并且修改src_new/a/b/c/d/file
的内容为
new_line1
new_line2
new_line3
此时,demo目录下用tree命令的结果是:
制作补丁
在demo目录下用diff命令打补丁,不要使用绝对路径,而应该使用相对路径。
diff -Nur src src_new >src.patch
关于diff
的用法,可以参考我的博文:
http://blog.csdn.net/longintchar/article/details/74139933
浏览一下补丁文件:
至此,补丁制作完成。
这时候在demo目录下用tree命令,得到
打补丁
在demo目录下,试试下面命令:
patch -p0 <src.patch
回车后终端显示
patching file src/a/b/c/d/file
这里的p0是什么含义呢?
看一下补丁文件中的路径信息:
--- src/a/b/c/d/file 2017-07-02 18:41:19.269641100 +0800
+++ src_new/a/b/c/d/file 2017-07-02 18:32:06.687035200 +0800
p0
表示不跳过任何目录(使用完整路径)。即从当前目录中查找src/a/b/c/d/file
.
因为是在demo目录下使用patch命令,src
目录就在demo目录下,不必跳过任何目录,所以此时使用的是p0
。
此时查看src/a/b/c/d/file
,你会发现内容已经修改成
new_line1
new_line2
new_line3
这时候如果再次使用patch命令,系统会问你是否想还原,输入y 还原:
patching file src/a/b/c/d/file
Reversed (or previously applied) patch detected! Assume -R? [n]
这时候src/a/b/c/d/file
的内容已经还原成旧的了:
line1
line2
line3
如果你想指定还原文件, 可以使用-R
参数:
patch -Rp0 <src.patch
已经明白了p0,那么p1、p2呢?
我们把路径切换到src
目录下。
cd src
此时就应该是p1,而不是p0了; 另外引用src.patch
文件的路径也要适当变一下,因为当前目录已经是src
了
patch -p1 <../src.patch
再看看补丁文件中的路径信息:
--- src/a/b/c/d/file 2017-07-02 18:41:19.269641100 +0800
+++ src_new/a/b/c/d/file 2017-07-02 18:32:06.687035200 +0800
此时我们是在src
目录下使用patch命令,p1
表示忽略第一个斜杠及左边,即寻找a/b/c/d/file
,而a
就在当前目录下,所以使用p1
.
为了继续测试,我们还原一下
patch -Rp1 <../src.patch
继续变换路径,测试p2参数:
cd a
然后
patch -p2 <../../src.patch
因为补丁文件中的路径信息是
--- src/a/b/c/d/file 2017-07-02 18:41:19.269641100 +0800
+++ src_new/a/b/c/d/file 2017-07-02 18:32:06.687035200 +0800
此时我们是在a
目录下使用patch命令,p2
表示忽略第2个斜杠及左边,即寻找b/c/d/file
,而b
就在当前目录下,所以使用p2
.
还原后继续实验,我们进入到d目录
patch -p5 <../../../../../src.patch
依然观察补丁文件中的路径信息:
--- src/a/b/c/d/file 2017-07-02 18:41:19.269641100 +0800
+++ src_new/a/b/c/d/file 2017-07-02 18:32:06.687035200 +0800
此时我们是在d
目录下使用patch命令,p5
表示忽略第5个斜杠及左边,即寻找file
,而file
就在当前目录下,所以使用p5
.
有人会问,不使用p参数会有什么结果呢?
不使用p
参数 时候,patch命令会忽略所有斜杠,直接使用文件,即本文中的file
所以在d
目录下也可以用命令
patch <../../../../../src.patch
为什么使用diff命令时最好不要使用绝对路径,而应该使用相对路径?
答:如果使用绝对路径,那么补丁文件里的路径信息会类似下面的样子:
--- /x/xx/xxx/src/a/b/c/d/file 2017-07-02 18:41:19.269641100 +0800
+++ /x/xx/xxx/src_new/a/b/c/d/file 2017-07-02 18:32:06.687035200 +0800
如此一来,当别人想应用你的补丁时,因为目录结构肯定有差异,所以就不得不费力判断到底使用p几。这样一来就容易出错.
相反,如果使用相对路径的话,大多数时候,p0或者p1就足够了,不易出错。
总结
假如补丁头是
--- src/a/b/c/d/file 2017-07-02 18:41:19.269641100 +0800
+++ src_new/a/b/c/d/file 2017-07-02 18:32:06.687035200 +0800
使用p0 表示在当前目录下查找src/a/b/c/d/file
使用p1 表示在当前目录下查找a/b/c/d/file
使用p2 表示在当前目录下查找b/c/d/file
使用p3 表示在当前目录下查找c/d/file
使用p4 表示在当前目录下查找d/file
使用p5 表示在当前目录下查找file
不使用pn表示忽略所有斜杠,在当前目录下查找file
打补丁的命令格式是
patch -pn < 补丁文件
还原的命令格式是
patch -Rpn < 补丁文件
(n=0,1,2,3…)
【参考资料】
[1] http://blog.csdn.net/wh_19910525/article/details/7515540