diff及patch的使用

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

创建补丁文件

所谓的补丁文件其实就是diff的输出,将其重定向至文件即可,生成的补丁文件习惯上使用.patch后缀。

常用参数如下:

1
diff -ruaN oldfile newfile > patchfile.patch

其中:

  • -r: 递归遍历子目录
  • -u: 使用合并格式输出
  • -a: 将所有文件视为文本文件
  • -N: 将未出现的文件视为空文件(比较目录时有用)

oldfilenewfile可以是一个目录,配合-r参数使用就会递归比较这两个目录。

示例

下面用一个例子来说明。

有以下文件目录:

1
2
3
4
5
6
7
.
├── new
│   ├── 1.txt
│   └── 2.txt
└── old
   ├── 1.txt
   └── 2.txt

old文件夹中存放的是老版本,new中是新版本。使用以下命令生成补丁文件:

1
diff -ruaN old new > update.patch

生成的update.patch文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
diff -aruN old/1.txt new/1.txt
--- old/1.txt 2016-10-19 00:12:51.572014429 +0800
+++ new/1.txt 2016-10-15 12:10:18.581633573 +0800
@@ -1,3 +1,3 @@
-old Line 1
-old Line 2
-old Line 3
+new Line 1
+new Line 2
+new Line 3
diff -aruN old/2.txt new/2.txt
--- old/2.txt 2016-10-19 00:12:51.572014429 +0800
+++ new/2.txt 2016-10-15 12:11:03.847494158 +0800
@@ -1,4 +1,4 @@
-Old Line 1
-Old Line 2
-Old Line 3
+New Line 1
+New Line 2
+New Line 3

需要注意的是,使用如下命令也可以生成补丁文件:

1
diff -aruN ./old ./new > update2.patch

但是生成的补丁文件是不一样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
diff -aruN ./old/1.txt ./new/1.txt
--- ./old/1.txt 2016-10-19 00:12:51.572014429 +0800
+++ ./new/1.txt 2016-10-15 12:10:18.581633573 +0800
@@ -1,3 +1,3 @@
-old Line 1
-old Line 2
-old Line 3
+new Line 1
+new Line 2
+new Line 3
diff -aruN ./old/2.txt ./new/2.txt
--- ./old/2.txt 2016-10-19 00:12:51.572014429 +0800
+++ ./new/2.txt 2016-10-15 12:11:03.847494158 +0800
@@ -1,4 +1,4 @@
-Old Line 1
-Old Line 2
-Old Line 3
+New Line 1
+New Line 2
+New Line 3

差异在于文件路径不同,这会导致之后使用patch打补丁时所需的命令有所区别,下文再讨论这一问题。

patch

应用补丁

1
patch < patchfile

一般不需要指定需要打补丁的文件,这个可以从patchfile中自动推导出来,就是文件中---部分的oldfilepatch命令会自动将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
2
3
4
5
6
7
8
9
can't find file to patch at input line 4
Perhaps you should have used the -p or --strip option?
The text leading up to this was:
--------------------------
|diff -aruN ./old/1.txt ./new/1.txt
|--- ./old/1.txt 2016-10-19 00:12:51.572014429 +0800
|+++ ./new/1.txt 2016-10-15 12:10:18.581633573 +0800
--------------------------
File to patch:

此时可以手动输入对应文件的路径./old/1.txt,然而这并不是一个好方法,正确的方法是使用-pNum参数:

1
patch -p1 < update2.patch

-p1表示去掉第一层路径分隔符,即./,此时得到的old文件夹位于当前路径中,于是就可以正确的打补丁了。

文章目录
  1. 1. diff
    1. 1.1. 基本用法
    2. 1.2. 输出格式
    3. 1.3. 创建补丁文件
    4. 1.4. 示例
  2. 2. patch
    1. 2.1. 应用补丁
    2. 2.2. 回滚补丁
    3. 2.3. 移去路径级别
    4. 2.4. 示例