Time: 2022.10.26
Tags: 开发
Linux 系统下默认提供的 diff 和 patch 命令,能够帮助我们清晰的对比两个文件之间的差异,并进行补丁操作;常见的代码版本控制工具(git/svn)的基本思想就是 diff 和 patch。
当面向没有代码版本控制的项目开发时,我们可以使用 diff 和 patch 这一组命令进行代码管理:使用 diff 命令制作补丁文件,使用 patch 命令对代码打补丁或还原代码;除此之外,补丁文件可以较为方便的传递给他人,能够以这种方式参与开源项目或分享代码补丁。Linux 早期开发也采用这种方式。
本文简单介绍 diff 和 patch 命令的基本使用。
diff 命令的基本操作:
diff <变动前的文件> <变动后的文件>
我们准备两个测试文件,file1
如下:
a b
b
c
d
e
f
g
h
file2
如下:
a b c
b
d
e
z
g
h
使用 diff 结果如下:
$ diff file1 file2
1c1
< a b
---
> a b c
3d2
< c
6c5
< f
---
> z
由于历史原因,diff有三种格式:
1.正常格式
diff 默认输出即为正常格式,所上所示;正常格式中以「修改块」为单位:
1c1
< a b
---
> a b c
第一行用于说明变动位置,第一个数字 1
表示 file1 的第 1 行有变化,第二个字符 c
表示变化的模式为内容改变(change
),其他模式还有增加(addition
)和删除(deletion
),最后一个数组 1
表示变动后为 file2 的第 1 行;
第二行分为两部分,<
字符表示要从 file1 中删除该行(也就是第 1 行),后面的 a b
表示删除的内容;
第三行 ---
时分割符,用于分割 file1 和 file2;
第四行和第二行类似,>
字符表示要在 file2 中增加改行,内容为 a b c
;
如果有多个修改块则在文件中顺序拼接。
2.上下文格式
diff 使用 --context
参数使用上下文格式输出:
$ diff -c file1 file2
*** file1 2022-10-26 12:00:00.000000000 +0800
--- file2 2022-10-26 12:01:00.000000000 +0800
***************
*** 1,8 ****
! a b
b
- c
d
e
! f
g
h
--- 1,7 ----
! a b c
b
d
e
! z
g
h
上下文格式可分为四个部分;
第一部分显示两个文件的基本情况,***
表示变动前的文件,---
表示变动后的文件:
*** file1 2022-10-26 12:00:00.000000000 +0800
--- file2 2022-10-26 12:01:00.000000000 +0800
第二部分是15个星号,将文件的基本情况与变动内容分割开:
***************
第三部分显示变动前的文件内容:
*** 1,8 ****
! a b
b
- c
d
e
! f
g
h
上下文模式不仅显示发生变化的那一行,还显示前后几行的信息(默认显示 7 行),其中 *** 1,8 ****
表示展示内容从第 1 行开始连续 8 行;
随后展示的是文件内容的变动,第一列为变化的模式:
随后为该行的内容;
第四部分显示变动后的文件内容,其格式和第三部分一致:
--- 1,7 ----
! a b c
b
d
e
! z
g
h
如果有多个修改块也在文件中顺序拼接,如果有多个文件的变动也可以写在一个文件中。
3.合并格式
上下文格式很好的解决了正常格式内容过于简单的问题,但是当两个文件相似度很高时,上下文格式就会出现大量的重复内容;合并格式则在上下文格式上做了优化。
diff 使用 --unified
参数使用上下文格式输出:
$ diff -u file1 file2
--- file1 2022-10-26 12:00:00.000000000 +0800
+++ file2 2022-10-26 12:01:00.000000000 +0800
@@ -1,8 +1,7 @@
-a b
+a b c
b
-c
d
e
-f
+z
g
h
合并格式可分为三个部分;
第一部分显示两个文件的基本情况,---
表示变动前的文件,+++
表示变动后的文件:
--- file1 2022-10-26 12:00:00.000000000 +0800
+++ file2 2022-10-26 12:01:00.000000000 +0800
第二部分表示变动的位置,用 @@
作为开始和结束标志:
@@ -1,8 +1,7 @@
-1,8
表示上下文是 file1 文件第 1 行开始的连续 8 行内容,+1,7
表示上下文是 file2 文件的第 1 行开始的连续 7 行内容;
第三部分表示具体的内容变化:
-a b
+a b c
b
-c
d
e
-f
+z
g
h
其中第一列表示变化的模式:
随后为该行的内容
同样如果有多个修改块可在文件中顺序拼接,如果有多个文件的变动也可以写在一个文件中。
PS:合并模式是目前使用得最多的格式。
使用 diff 命令将结果重定向到文件,就生成了补丁文件,patch 命令可以根据其内容进行打补丁(对于上文中不同的 diff 格式,patch 都能够正常工作,这里我们以合并格式为例):
$ diff -u file1 file2 > a.diff
$ cat a.diff
--- file1 2022-10-26 12:00:00.000000000 +0800
+++ file2 2022-10-26 12:01:00.000000000 +0800
@@ -1,8 +1,7 @@
-a b
+a b c
b
-c
d
e
-f
+z
g
h
使用 patch 命令对 file1 进行打补丁操作如下:
$ patch file1 a.diff
patching file file1
$ cat file1
a b c
b
d
e
z
g
h
随后我们再使用 patch 命令取消 file1 的补丁内容:
$ patch -R file1 a.diff
patching file file1
$ cat file1
a b
b
c
d
e
f
g
h
在某些时候,代码版本控制出现错误或者用户误操作,可能导致 patch 打补丁失败,如果发生失败则会在当前目录下生成 [filename.orig]
和 [filename].rej
,orig
为文件的原始内容,rej
文件则发生错误的补丁内容,可根据 rej
文件分析错误原因。
除此之外,diff 和 patch 还可以对整个目录进行补丁操作。
https://www.ruanyifeng.com/blog/2012/08/how_to_read_diff.html
https://www.cnblogs.com/053179hu/p/14665795.html
http://linux-wiki.cn/wiki/zh-hans/%E8%A1%A5%E4%B8%81(patch)%E7%9A%84%E5%88%B6%E4%BD%9C%E4%B8%8E%E5%BA%94%E7%94%A8