=====读懂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相同。