温馨提示:
本文所述内容具有依赖性,可能因软硬条件不同而与预期有所差异,故请以实际为准,仅供参考。
比如 ArmxMod for Typecho 主题,存在较多子目录及文件,有时候小伙伴们会再这个基础上进行再次开发,担心在主题更新后,直接覆盖掉会忘了修改了什么地方,所以就在想,是否由办法通过打补丁(patch)的方式进行更新。
经过查询,Linux 下生成补丁和打补丁可以通过 diff
和 patch
两个命令来实现。
生成补丁
生成补丁很重要的一个基础,就是需要有一份未修改的源码,然后通过 diff
命令生成差异,参考如下代码:
[root@lc-bj themes]# diff -uprN armx/ armxnew/ >>0828-0905.patch
这一行命令实现的功能就是,对未修改的文件夹 armx
和修改后的文件夹 armxnew
,递归文件夹输出差异行至 08228-0905.patch
文件中。
-u 显示有差异行的前后几行(上下文),默认是前后各 3 行,这样,patch中带有更多的信息;
-p 显示代码所在的 c 函数的信息;
-r 递归地对比一个目录和它的所有子目录(即整个目录树);
-N 如果某个文件缺少了,就当作是空文件来对比。如果不使用本选项,当 diff 发现旧代码或者新代码缺少文件时,只简单的提示缺少文件,如果使用本选项,会将新添加的文件全新打印出来作为新增的部分。
生成的补丁大概长这样:
......
diff -uprN armx/css/style.css armxnew/css/style.css
--- armx/css/style.css 2019-08-27 11:12:54.000000000 +0800
+++ armxnew/css/style.css 2019-09-05 11:41:14.000000000 +0800
@@ -2538,7 +2538,7 @@ padding: 0px;
.tl-item div{
margin-top: 0px!important;
}
-#tabs-recom img:hover,#tabs-service img:hover,#tabs-recom .recdiv:hover,#tabs-service .recdiv:hover {
+#tabs-recom img:hover,#tabs-service img:hover, #tabs-recom .recdiv:hover,#tabs-service .recdiv:hover{
box-shadow: 0 0 25px 8px rgba(0,0,0,.33);
transform: scale(1.2);
border-radius: 5px;
......
其中 @@ -2538,7 +2538,7 @@
被称为 (c) 更改块的范围信息,其格式如下:
@@ -l,s +l,s @@
其中 l
是起始行号,s
是更改块在文件中的行数。 -
表示原始文件,+
表示新文件,请注意,它不仅显示受影响的行,而且还显示上下行。
这一句的意思就是从第 2538
行开始,共显示 7
行。-
表示该行将被删除,+
表示该行将会新增插入。
打补丁
打补丁的意义在于批量修改更新的文件,而不去动没有修改的文件。从上面生成补丁可以看到,补丁的重要参数是行数,因此如要成功打上补丁,行数要能对上才行。
生成的补丁中,路径信息包含了源码根目录的名称,但其他人的源码根目录可能是其它名字,所以打补丁时,要进入自己的源码根目录,并且告诉 patch
,请忽略补丁中的路径的第一级目录(参数 -p1
),参考如下代码:
[root@lc-bj armx]# patch -p1 <0828-0905.patch
patching file comments.php
patching file css/style.css
patching file footer.php
patching file functions.php
patching file header.php
patching file index.php
patching file js/main.js
patching file js/script.js
patching file lib/online.txt
patching file lib/smaile.php
可以看到已经成功将差异部分更新到自己源码中了。
二进制补丁
在实际应用中,会发现,只有源代码成功被打补丁,新增的图片并没有更新到,查看补丁文件,可以发现错误信息:
......
Binary files armx/img/ravatar/0.jpg and armxnew/img/ravatar/0.jpg differ
Binary files armx/img/ravatar/1.jpg and armxnew/img/ravatar/1.jpg differ
Binary files armx/img/ravatar/2.jpg and armxnew/img/ravatar/2.jpg differ
......
可以确定在生成补丁时,并没有将图片纳入,故判断命令 diff -uprN
不支持非文本格式,经查询使用手册,我们可以加上 -a
来使其使用二进制的方式来支持非文本格式的修改,比如图片等等。
结论
所以最终生成补丁的命令是(注意执行目录是 themes/
):
[root@lc-bj themes]# diff -auprN armx/ armxnew/ > 0828-0905.patch
[root@lc-bj themes]# mv 0828-0905.patch armx/
打补丁的命令是(注意执行目录是 themes/armx
):
[root@lc-bj armx]# patch -p1 <0828-0905.patch
patching file comments.php
patching file css/style.css
patching file footer.php
patching file functions.php
patching file header.php
patching file img/hw818_2.png
patching file img/ravatar/0.jpg
patching file img/ravatar/1.jpg
patching file img/ravatar/2.jpg
patching file img/ravatar/3.jpg
patching file img/ravatar/4.jpg
patching file img/ravatar/5.jpg
patching file img/ravatar/6.jpg
patching file img/ravatar/7.jpg
patching file img/ravatar/8.jpg
patching file img/ravatar/9.jpg
patching file index.php
patching file js/main.js
patching file js/script.js
patching file lib/online.txt
patching file lib/smaile.php
思考
使用 diff
和 patch
命令来完成生成补丁和打补丁动作,本质上其实跟 git
版本管理类似,由于补丁都是基于源文件进行的,因此如果源文件被修改,恰好这个文件又是有更新的,那么基于源文件的补丁将无法使用。
有一个折中的方法,就是先将修改过的部分做个补丁,标记出修改了什么地方,然后覆盖最新的源码,根据补丁再把修改的地方再做一遍,囧。。。
通过打补丁方式来更新,工作量少,可以较好实现版本控制。