读懂diff
在linux命令和一些文件比较,版本控制软件中,都会用到diff。它用来比较两个文本文件的差异,是代码版本管理的基石之一。
Linux命令中的diff
由于历史原因,diff有三种格式:
* 正常格式(normal diff) * 上下文格式(context diff) * 合并格式(unified diff)
在linux命令下比较两个文件的差异,用的是正常格式。比如我们创建一个五行都是一个a的文件test1.txt,然后复制它为test2.txt,并把第三行改为b。
diff test1.txt test2.txt
输出结果为正常格式的diff:
3c3 < a --- > b
其中,第一行说明变动位置,第一个3说明test1.txt的第三行有变动,中间c表示文本变动,后面的3表示变动为test2.txt的第3行。
下面一行,前面<号去掉这一行,再接着是分隔线,接下来一行>号表示变动后加上这一行。
上个世纪80年代初,加州大学伯克利分校推出BSD版本的Unix时,觉得diff的显示结果太简单,因此加入上下文以了解变动情况,在今天的Linux中, 如果我们在上面的命令中加入参数c,也就是用
diff -c test1.txt test2.txt
则变成输出上下文格式的diff
*** test1.txt 2017-01-11 14:38:20.379006066 +0800 --- test2.txt 2017-01-11 14:19:20.303265901 +0800 *************** *** 1,5 **** a a ! a a a --- 1,5 ---- a a ! b a a
在连续15个*号之前,是文件的基本信息,***表示变动前的文件,—表示变动后的文件,两个文件变动的部分的上下文都列了出来。上下文一般是列出变动前后的三行,我们这里因为一共只有5行,所以上下文只列变动前后的两行。每一行前面有个标记位,如果为空,表示该行无变化;如果是感叹号(!),表示该行有改动;如果是减号(-),表示该行被删除;如果是加号(+),表示该行为新增。
如果两个文件相似度很高,那么上下文格式的diff,将显示大量重复的内容,很浪费空间。1990年,GNU diff率先推出了“合并格式”的diff。 在diff命令中,使用-u参数
diff -u test1.txt test2.txt
输出变成:
--- test1.txt 2017-01-11 14:38:20.379006066 +0800 +++ test2.txt 2017-01-11 14:19:20.303265901 +0800 @@ -1,5 +1,5 @@ a a -a +b a a
可以看到,它保留了文件的基本信息,并把上下文合并了,用@@ -1,5 +1,5 @@ 这一行,-号表示第一个文件(或变动前文件)从第1行到第5行,+号则表示第二个文件(或变动后文件)的位置从第1行到第5行。在接下来的文件信息中,同样列出变动前后的三行,和前后的变动信息。每一行最前面的标志位,空表示无变动,减号表示第一个文件删除的行,加号表示第二个文件新增的行。
git格式的diff
版本管理系统git,使用的是合并格式diff的变体。
mkdir test cd test git init nano test 这里输入10行a
上面新建一个test目录,并初始化为git仓库目录,用创建一个test文件,输入10行a,保存
git add test git commit nano test 把第5行改为b git diff
这时输出的就是git的diff了
diff --git a/test b/test index d15112c..1a91ab8 100644 --- a/test +++ b/test @@ -2,7 +2,7 @@ a a a a -a +b a a a
第一行表示结果为git格式的diff。进行比较的是,a版本的test(即变动前)和b版本的test(即变动后)。 第二行表示两个版本的git哈希值(index区域的d15112c对象,与工作目录区域的1a91b8对象进行比较),最后的六位数字是对象的模式(普通文件,644权限)。“—“表示变动前的版本,”+++“表示变动后的版本。后面的行都与官方的合并格式diff相同。