diff和patch
diff和patch是一对好基友。diff用于产生两个文件(或者说一个文件的两个版本)之间的差异补丁,patch用于应用补丁,从而使文件从一个版本变迁到另一个版本。
diff
diff命令生成的补丁有多种格式,目前最常用的是unified context格式。
用法:
1 | $ diff -Nur file1 file2 > patchfile |
命令行参数:
1 | -N,--new-file 如果比较时找不到其中的一个文件,则找不到的文件视为空文件 |
生成的补丁文件格式:
1 | --- file1 2014-02-24 13:35:58.441441353 +0800 |
其中:
第一行指明变动前的旧文件,后面是文件的时间戳,包括时区。
第二行指明变动后的新文件
第三行指明变动的起始行和变动的范围。-1,5表明旧文件影响从第一行开始的5行范围,+1,7表示新文件影响从第一行开始的7行。
注意默认输出变动行前后的3行作为上下文,上下文也是包含在范围之内的。
最后就是实际的变动内容。行前面有-号的表示删除的号,有+号的表示添加的号,其他没有前缀符号的是上下文。
patch
patch命令应用差异补丁,从而使文件从一个版本变迁到一个新的版本。
用法:
1 | $ patch -p\[num\] < patchfile |
参数:
1 | -pnum or --strip=num 从补丁文件中读出的文件名剥除掉num指定个数的前导斜线(/),如果有两个连续的斜线视为一个剥除。 |
git diff和git apply
git diff命令可以比较两个提交之间,两个分支之间,提交和工作目录之间,未暂存(staged)的更改与提交之间等等的差异。
- 尚未暂存的文件差异如果不指定文件名则比较所有的文件
1
$ git diff \[filename\]
- 暂存的文件和上次提交之间的差异如果不指定文件名则比较所有的文件
1
$ git diff --cached \[filename\]
- 两个提交之间的差异比较两个提交之间的差异,不指定文件名则比较所有的文件。通过hash值来指定对应的提交。
1
$ git diff d2909531\[:filename\] c940bcfd\[:filename\]
- 两个分支之间的差异比较master分支与devel分支的差异,
1
$ git diff master..devel
或者更简单的比较当前分支与devel分支的差异:1
$ git diff devel
git diff生成补丁文件是unified context格式的变体:
1 | diff --git a/js/dwz.tree.js b/js/dwz.tree.js |
第一行表示这是git diff格式的补丁文件,比较的文件为a版本的js/dwz.tree.js(变动前)和b版本的js/dwz.tree.js(变动后)
第二行指定两个版本文件的hash值和文件的模式(普通文件,访问权限为644)
其他与普通的unified context格式补丁文件一样。
因为使用a/和b/来标识两个版本,因此使用patch命令时需要将a/和b/剥除。
git diff生成的补丁可以使用patch也可以使用git apply来应用。
git format-patch和git am
git format-patch生成的是邮件格式的git专用补丁文件,包含了更丰富的信息,需要使用git am来应用这种格式的补丁。
注意
如果在windows和linux之间使用diff和patch,一定要注意这两个平台之间行结束符的不同,明明看上其相同的两行,diff和patch会认为是不同的行,从而出现错误。
比如提示这样的错误:
1 | Hunk #1 FAILED at xx (different line endings). |
windows下的行结束符为’/r/n’,而linux的行结束符为’/n’。
使用diff命令时可以使用参数-w, --ignore-all-space
忽略所有的空白,包括tab,carriage return,newline,vertical tab,form feed和space。
使用patch命令时可以使用参数-l,--ignore-whitespace
来进行松散匹配,但这参数只忽略tab和space。
最好还是使文件的格式一致,vim里可以使用:set fileformat修改文件格式,比如修改为unix或dos格式:
1 | :set fileformat=unix |
references:
[1]读懂diff
===
[erq]