1 背景
作为一个程序员,经常需要阅读并且修改代码,因此必须得懂得如何制作补丁和打补丁。
2 制作补丁——diff[1]
制作补丁,一般使用diff工具,例如:
2.1 文件
diff –uN from_file to_file > to_file.patch
参数解析:
-u, -U NUM, --unified[=NUM]:输出NUM (默认 3) 行合并格式说明信息,如下面的例子所示。diff支持3种格式,详见参考资料[4];
-N, --new-file:若文件不存在,则当作是新文件,内容为空。
统一格式说明:
--- file_new.c 2015-10-05 16:54:38.002595128 +0800 +++ file_old.c 2015-10-05 16:54:25.378595412 +0800 @@ -1,8 +1,7 @@
格式说明:
---:旧文件[1]
+++:新文件[1]
2.2 目录
diff –uNr from_dir to_dir > to_dir.patch
参数解析:
-r, --recursive:递归比较子目录的文件。
2.3 补丁文件结构[1]
2.3.1 补丁头
补丁头是分别由---/+++开头的两行,用来表示要打补丁的文件。---开头表示旧文件,+++开头表示新文件。
一个补丁文件中可能包含以---/+++开头的很多节,每一节用来打一个补丁。所以在一个补丁文件中可以包含好多个补丁。
具体实例如2.1小节所示。
2.3.2 块
块是补丁中要修改的地方。它通常由一部分不用修改的东西开始和结束。他们只是用来表示要修改的位置。他们通常以@@开始,结束于另一个块的开始或者一个新的补丁头。
块会缩进一列,这一列是用来表示这一行是要增加还是要删除的:
+号表示这一行是要加上的;
-号表示这一行是要删除的。
没有加号也没有减号表示这里只是引用的而不需要修改。
2.4 实例
2.4.1 file_old.c
#include <stdio.h> int main(void) { printf("hello world !\n"); printf("How are you ?\n"); }
2.4.2 file_new.c
#include <stdio.h> int main(void) { //printf("hello world !\n"); printf("How are you ?\n"); printf("I am fine!\n"); }
2.4.3 diff -uN file_old.c file_new.c
liyihai@ubuntu:~/Documents/patch_example$ diff -u file_old.c file_new.c --- file_old.c 2015-10-05 16:54:25.378595412 +0800 +++ file_new.c 2015-10-05 16:54:38.002595128 +0800 @@ -1,7 +1,8 @@ #include <stdio.h> int main(void) { - printf("hello world !\n"); + //printf("hello world !\n"); printf("How are you ?\n"); + printf("I am fine!\n"); }
说明:若使用上述内容作为补丁文件,则打补丁的时候是对file_old.c进行打补丁,使其内容和file_new.c一致。
2.4.4 diff -uN file_new.c file_old.c
liyihai@ubuntu:~/Documents/patch_example$ diff -u file_new.c file_old.c --- file_new.c 2015-10-05 16:54:38.002595128 +0800 +++ file_old.c 2015-10-05 16:54:25.378595412 +0800 @@ -1,8 +1,7 @@ #include <stdio.h> int main(void) { - //printf("hello world !\n"); + printf("hello world !\n"); printf("How are you ?\n"); - printf("I am fine!\n"); }
说明:若使用上述内容作为补丁文件,则打补丁的时候是对file_new.c进行打补丁,使其内容和file_old.c一致。
3 打/去除补丁——patch
3.1.文件[1]
进入需要需要打补丁的文件所在的目录,执行下面的命令:
diff –uN old_file new_file > new.patch //生成补丁 【因为单个文件,所以不需要-r选项。选项顺序没有关系,即可以是-uN,也可以是-Nu】 patch –p0 < new.patch //打补丁 patch –R –p0 < new.patch //去除补丁参数解析:
-p0:忽略0层目录(即没有忽略)[1]。想要忽略几层目录,就将0改为相应的数字行了。
-R, --reverse:反向操作。打补丁的反向操作就是去除补丁。
3.2 目录[1]
diff –uNr old_dir new_dir > new.patch //生成补丁 cd old_dir patch –p1 < new.patch //打补丁 patch –R –p1 < new.patch //去除补丁
参数说明:
-p1:表示忽略1层目录。如果cd old_dir再执行patch,一般要使用这个参数,否则会在old_dir中再创建一个顶层的目录(就像Windows中使用rar解压工具解压文件时,如果指定“解压到xxx目录”,则会在xxx目录中创建一个与解压文件同名的目录,然后再将解压的内容保存到其中。这样子往往就多了一层目录,并非我们所需要的!)
参考资料
[1]使用diff命令打补丁详解
[2]使用diff和patch制作及打补丁
[3]diff和patch使用指南
[4]读懂diff
[5]如何使用git 生成patch
[6]git diff的用法
[7]如何用git-am来合并git format-patch生成的一系列的patch
[8]Git的Patch功能