Linux下,diff
命令用于比较两个文件的差异,也可用于创建补丁文件,而patch
命令用于打补丁,也就是应用diff
命令生成的补丁文件更新现有文件。下面简要总结下这两个命令的使用方法。
diff
基本用法
1 | diff oldfile newfile |
注意:diff
命令是按行比较两个文本文件的,所以一般只用它比较两个基本相同的文本文件,如同一份源代码的不同版本。
输出格式
diff
一共有3种输出格式:
- 正常格式(normal diff)
- 上下文格式(context diff)
- 合并格式(unified diff)
一般使用合并格式,这种格式比较适合阅读,加上-u
参数即可:
1 | diff -u f1 f2 |
关于diff
的输出格式详细说明可参考:
创建补丁文件
所谓的补丁文件其实就是diff
的输出,将其重定向至文件即可,生成的补丁文件习惯上使用.patch
后缀。
常用参数如下:
1 | diff -ruaN oldfile newfile > patchfile.patch |
其中:
- -r: 递归遍历子目录
- -u: 使用合并格式输出
- -a: 将所有文件视为文本文件
- -N: 将未出现的文件视为空文件(比较目录时有用)
oldfile
及newfile
可以是一个目录,配合-r
参数使用就会递归比较这两个目录。
示例
下面用一个例子来说明。
有以下文件目录:
1 | . |
old
文件夹中存放的是老版本,new
中是新版本。使用以下命令生成补丁文件:
1 | diff -ruaN old new > update.patch |
生成的update.patch
文件如下:
1 | diff -aruN old/1.txt new/1.txt |
需要注意的是,使用如下命令也可以生成补丁文件:
1 | diff -aruN ./old ./new > update2.patch |
但是生成的补丁文件是不一样的:
1 | diff -aruN ./old/1.txt ./new/1.txt |
差异在于文件路径不同,这会导致之后使用patch
打补丁时所需的命令有所区别,下文再讨论这一问题。
patch
应用补丁
1 | patch < patchfile |
一般不需要指定需要打补丁的文件,这个可以从patchfile
中自动推导出来,就是文件中---
部分的oldfile
,patch
命令会自动将newfile
中的变更应用于oldfile
上。
回滚补丁
1 | patch -R < patchfile |
回滚补丁的意思是在对oldfile
应用了补丁后,又需要取消这个补丁,即回滚到oldfile
原始的状态。
移去路径级别
上面的用法中均是假定patchfile
中的路径是正确的,然而很多时候这个路径会包含不需要的目录级别,这时就需要用-pNum
参数来移去多余的路径级别:
1 | patch -pNum < patchfile |
这里的Num
是一个数字,如-p1
、-p2
等。p级别告诉patch
命令忽略掉路径名的前几个部分以正确的识别文件,总的来说,从路径最开始删除路径分隔符(/
)及其之前的所有字符,每次加1,直到剩下的部分存在于当前工作目录中,最后得到的就是p级别。 具体使用方法见下文的示例。
示例
接着上文diff
命令中的示例进行,此时我们已经有了补丁文件update.patch
,下面来应用这个补丁,使用以下命令即可:
1 | patch < update.patch |
这样既可将old
文件夹中的内容更新为new
文件夹中的内容。
如果需要回滚补丁,即恢复old
文件夹中的原始内容,使用以下命令:
1 | patch -R < update.patch |
不过针对update2.patch
文件,如果直接使用上述命令打补丁会报错:
1 | can't find file to patch at input line 4 |
此时可以手动输入对应文件的路径./old/1.txt
,然而这并不是一个好方法,正确的方法是使用-pNum
参数:
1 | patch -p1 < update2.patch |
-p1
表示去掉第一层路径分隔符,即./
,此时得到的old
文件夹位于当前路径中,于是就可以正确的打补丁了。