diff 与 patch 的使用

简介:

在 Linux 的日常使用中,我们经常需要修改一些配置文件,然而在软件升级以后,经常会面临配置更新后与原配置部分不兼容的问题(当然我们更多的可能是来制作软件升级的补丁)。在这种情况下我们通常有两种选择:

d47e62d2b349aca45e42305ed6714efbe5ed61d9 对比现有配置,手动在新配置文件中改动
d47e62d2b349aca45e42305ed6714efbe5ed61d9 利用 sed awk 等工具配合改动
d47e62d2b349aca45e42305ed6714efbe5ed61d9 采用 diff patch 制作增量补丁的方式改动

本文主要通过一个升级awesome 配置的例子,对第三种方法进行介绍和讲解。

diff 介绍

diff 是一个文件比较工具,可以逐行比较两个文件的不同,其中它有三种输出方式,分别是 normalcontext 以及 unified。区别如下:

d47e62d2b349aca45e42305ed6714efbe5ed61d9normal 方式为默认输出方式,不需要加任何参数
d47e62d2b349aca45e42305ed6714efbe5ed61d9context 相较于 normal 模式的简单输出, contetx 模式会输出修改过部分的上下文,默认是前后 3 行。使用参数 -c
d47e62d2b349aca45e42305ed6714efbe5ed61d9unified 合并上下文模式则为新的上下文输出模式,同样为前后 3 行,只不过把上下文合并了显示了。使用参数 -u

:本文主要介绍 unified 模式

其他常用参数:

d47e62d2b349aca45e42305ed6714efbe5ed61d9-r 递归处理目录

d47e62d2b349aca45e42305ed6714efbe5ed61d9-N 将缺失的文件当作空白文件处理

diff 语法与文件格式

 
  1. diff [options] old new

先来看一个简单的例子:

 
  1. $ cat test1
  2. linux
  3. linux
  4. linux
  5. linux
 
  1. $ cat test2
  2. locez
  3. linux
  4. locez
  5. linux

此时输入 diff -urN test1 test2 会输出以下信息:

 
  1. --- test1 2018-05-12 18:39:41.508375114 +0800
  2. +++ test2 2018-05-12 18:41:00.124031736 +0800
  3. @@ -1,4 +1,4 @@
  4. +locez
  5. linux
  6. -linux
  7. -linux
  8. +locez
  9. linux

先看前面 2 行,这两行为文件的基本信息,--- 开头为改变前的文件,+++ 开头为更新后的文件。

 
  1. --- test1 2018-05-12 18:39:41.508375114 +0800
  2. +++ test2 2018-05-12 18:41:00.124031736 +0800

第三行为上下文描述块,其中 -1,4 为旧文件的 4 行上下文,+1,4 为新文件的:

 
  1. @@ -1,4 +1,4 @@

而具体到块里面的内容,前面有 - 号的则为删除,有 + 号为新增,不带符号则未做改变,仅仅是上下文输出。

patch 介绍

patch 是一个可以将 diff 生成的补丁应用到源文件,生成一个打过补丁版本的文件。语法:

 
  1. patch [oiption] [originalfile [patchfile]]

常用参数:

d47e62d2b349aca45e42305ed6714efbe5ed61d9-i 指定补丁文件
d47e62d2b349aca45e42305ed6714efbe5ed61d9-pNum diff 生成的补丁中,第一二行是文件信息,其中文件名是可以包含路径的,例如 --- /tmp/test1 2018-05-12 18:39:41.508375114 +0800 d47e62d2b349aca45e42305ed6714efbe5ed61d9 -p0 代表完整的路径 /tmp/test1 ,而 -p1 则指 tmp/test1 -pN 依此类推
d47e62d2b349aca45e42305ed6714efbe5ed61d9-E 删除应用补丁后为空文件的文件

d47e62d2b349aca45e42305ed6714efbe5ed61d9-o 输出到一个文件而不是直接覆盖文件

应用

awesome 桌面 3.5 与 4.0 之间的升级是不兼容的,所以在升级完 4.0 以后,awesome 桌面部分功能无法使用,因此需要迁移到新配置,接下来则应用 diffpatch 实现迁移,当然你也可以单纯使用 diff 找出不同,然后手动修改新配置。

现在有以下几个文件:

d47e62d2b349aca45e42305ed6714efbe5ed61d9rc.lua.3.5 3.5 版本的默认配置文件,未修改
d47e62d2b349aca45e42305ed6714efbe5ed61d9rc.lua.myconfig 基于 3.5 版本的个人配置文件
d47e62d2b349aca45e42305ed6714efbe5ed61d9rc.lua.4.2 4.2 新默认配置,未修改

思路为利用 diff 提取出个人配置与 3.5 默认配置文件的增量补丁,然后把补丁应用在 4.2 的文件上实现迁移。

制作补丁

  1. $ diff -urN rc.lua.3.5 rc.lua.myconfig > mypatch.patch

patch应用补丁

 
  1. $ patch rc.lua.4.2 -i mypatch.patch -o rc.lua
  2. patching file rc.lua (read from rc.lua.4.2)
  3. Hunk #1 FAILED at 38.
  4. Hunk #2 FAILED at 55.
  5. Hunk #3 succeeded at 101 with fuzz 1 (offset 5 lines).
  6. Hunk #4 succeeded at 276 with fuzz 2 (offset 29 lines).
  7. 2 out of 4 hunks FAILED -- saving rejects to file rc.lua.rej

显然应用没有完全成功,其中在 38 行以及 55 行应用失败,并记录在 rc.lua.rej 里。

 
  1. $ cat rc.lua.rej
  2. --- rc.lua.3.5 2018-05-12 19:15:54.922286085 +0800
  3. +++ rc.lua.myconfig 2018-05-12 19:13:35.057911463 +0800
  4. @@ -38,10 +38,10 @@
  5. -- {{{ Variable definitions
  6. -- Themes define colours, icons, font and wallpapers.
  7. -beautiful.init("@AWESOME_THEMES_PATH@/default/theme.lua")
  8. +beautiful.init("~/.config/awesome/default/theme.lua")
  9. -- This is used later as the default terminal and editor to run.
  10. -terminal = "xterm"
  11. +terminal = "xfce4-terminal"
  12. editor = os.getenv("EDITOR") or "nano"
  13. editor_cmd = terminal .. " -e " .. editor
  14. @@ -55,18 +55,18 @@
  15. -- Table of layouts to cover with awful.layout.inc, order matters.
  16. local layouts =
  17. {
  18. - awful.layout.suit.floating,
  19. - awful.layout.suit.tile,
  20. - awful.layout.suit.tile.left,
  21. - awful.layout.suit.tile.bottom,
  22. - awful.layout.suit.tile.top,
  23. +-- awful.layout.suit.floating,
  24. +-- awful.layout.suit.tile,
  25. +-- awful.layout.suit.tile.left,
  26. +-- awful.layout.suit.tile.bottom,
  27. +-- awful.layout.suit.tile.top,
  28. awful.layout.suit.fair,
  29. awful.layout.suit.fair.horizontal,
  30. awful.layout.suit.spiral,
  31. awful.layout.suit.spiral.dwindle,
  32. awful.layout.suit.max,
  33. awful.layout.suit.max.fullscreen,
  34. - awful.layout.suit.magnifier
  35. +-- awful.layout.suit.magnifier
  36. }
  37. -- }}}

这里是主题,终端,以及常用布局的个人设置。

修正补丁

再次通过对比补丁文件与 4.2 文件,发现 38 行区块是要删除的东西不匹配,而 55 行区块则是上下文与要删除的内容均不匹配,导致不能应用补丁,于是手动修改补丁

 
  1. $ vim mypatch.patch
 
  1. --- rc.lua.3.5 2018-05-12 19:15:54.922286085 +0800
  2. +++ rc.lua.myconfig 2018-05-12 19:13:35.057911463 +0800
  3. @@ -38,10 +38,10 @@
  4. -- {{{ Variable definitions
  5. -- Themes define colours, icons, font and wallpapers.
  6. -beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
  7. +beautiful.init("~/.config/awesome/default/theme.lua")
  8. -- This is used later as the default terminal and editor to run.
  9. -terminal = "xterm"
  10. +terminal = "xfce4-terminal"
  11. editor = os.getenv("EDITOR") or "nano"
  12. editor_cmd = terminal .. " -e " .. editor
  13. @@ -55,18 +55,18 @@
  14. -- Table of layouts to cover with awful.layout.inc, order matters.
  15. awful.layout.layouts = {
  16. - awful.layout.suit.floating,
  17. - awful.layout.suit.tile,
  18. - awful.layout.suit.tile.left,
  19. - awful.layout.suit.tile.bottom,
  20. - awful.layout.suit.tile.top,
  21. +-- awful.layout.suit.floating,
  22. +-- awful.layout.suit.tile,
  23. +-- awful.layout.suit.tile.left,
  24. +-- awful.layout.suit.tile.bottom,
  25. +-- awful.layout.suit.tile.top,
  26. awful.layout.suit.fair,
  27. awful.layout.suit.fair.horizontal,
  28. awful.layout.suit.spiral,
  29. awful.layout.suit.spiral.dwindle,
  30. awful.layout.suit.max,
  31. awful.layout.suit.max.fullscreen,
  32. - awful.layout.suit.magnifier,
  33. +-- awful.layout.suit.magnifier,
  34. awful.layout.suit.corner.nw,
  35. -- awful.layout.suit.corner.ne,
  36. -- awful.layout.suit.corner.sw,
  37. ....
  38. ....

输出省略显示,有兴趣的读者可以仔细与rc.lua.rej 文件对比,看看笔者是怎样改的。

再次应用补丁

 
  1. $ patch rc.lua.4.2 -i mypatch.patch -o rc.lua
  2. patching file rc.lua (read from rc.lua.4.2)
  3. Hunk #1 succeeded at 41 (offset 3 lines).
  4. Hunk #2 succeeded at 57 with fuzz 2 (offset 2 lines).
  5. Hunk #3 succeeded at 101 with fuzz 1 (offset 5 lines).
  6. Hunk #4 succeeded at 276 with fuzz 2 (offset 29 lines).
  7. $ cp rc.lua ~/.config/awesome/rc.lua ### 打完补丁直接使用

总结

diff 与 patch 配合使用,能当增量备份,而且还可以将补丁分发给他人使用,而且在日常的软件包打补丁也具有重要的意义,特别是内核补丁或者一些驱动补丁,打补丁遇到错误时候可以尝试自己修改,已满足自身特殊要求,修改的时候一定要抓住 2 个非常重要的要素:

d47e62d2b349aca45e42305ed6714efbe5ed61d9 要修改的内容是否匹配?特别是要删除的

d47e62d2b349aca45e42305ed6714efbe5ed61d9上下文是否满足,特别是距离要修改的地方前后一行,以及上下文的行数是否满足,默认是 3 行上下文


原文发布时间为:2018-06-4

本文来自云栖社区合作伙伴“Linux中国开源社区”,了解相关信息可以关注“Linux中国开源社区”。

相关文章
|
开发工具 git
git diff 生成patch合入代码
git diff 生成patch合入代码
621 0
|
Unix Linux Shell
patch 命令用法详解(转)
patch,是打补丁的命令,有很多用法,见帮助#man patch patch -p0       (“p”指的是路径,后面的数字表示去掉路径的第几部分。"0",表示不去掉,为全路径) patch -p1       (“p”后面的数字"1",表示去掉前第一个路径) fetch http://people.
9912 0
|
6月前
|
Linux
diff与patch的使用
diff与patch的使用
49 1
|
前端开发 API
patch使用
+ put:对所有资源进行更新 + patch:对部分资源进行更新 put使用方法和post相同,但是put是幂等的。
|
移动开发
diff和patch的使用简介
diff和patch的使用简介
|
开发工具 git
生成patch
生成patch
|
Linux Shell 开发工具
使用 diff 和 patch 命令协同开发
使用 diff 和 patch 命令协同开发
181 0
使用 diff 和 patch 命令协同开发
|
监控
Dispatch Source 应用
Dispatch Source 源是一个偏底层的函数集合,使用时CPU负荷非常小,尽量不占资源,开发过程中大多是配合定时器使用。
196 0
|
Android开发
一分钟学会使用9-patch
背景 之前项目开发一般都是写逻辑,UI方面的操作用的比较少。 图片也是直接使用设计师提供的。 因此一般情况下不需要用到9-patch图。 然而,最近项目中分配给我的功能用到了。
1559 0