Git中的diff命令可以显示文件之间的差异,同时-r选项可以遍历两个树对象,同时显示它们的差异。
从Git中的对象类型上看,一个树对象值只代表版本库中的一个目录层级,它包含该目录下的直接文件和它的所有直接子目录的信息,但不包括所有子目录的完整内容。而树对象引用所有子目录的树对象,所以对应项目根目录的树对象实际上代表某个时刻的整个项目,因此也可以说,git diff遍历两棵树。
存在三个可供树或类树对象使用git diff命令的基本来源:
通常情况下,git diff命令进行树的比较时可以通过提交名,分支名或标签名,同时,工作目录的文件和目录结构还有在索引中暂存文件的完整结构,都可以被看为树。
而git diff命令就可以使用上述三种来源的组合来进行如下4中基本比较:
命令行的参数个数决定使用哪种基本形式和比较什么。可以比较任意两个提交或树,比较的两个对象不需要有直接的或间接的父子关系。如果省略了一个或两个参数,那么git diff命令会比较默认的对象,比如工作目录,索引,HEAD等。
除了这几种基本形式的git diff命令外,还有一些比较有用的选项:
首先在空目录下初始化版本库:
- git init
- echo abc > file1
- git add file1
- git commit -m "commit file1"
- echo abcd > file2
- git add file2
- git commit -m "commit file2"
然后执行:
- $ echo 1111 > file1
-
- $ git diff
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- diff --git a/file1 b/file1
- index 8baef1b..5f2f16b 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -abc
- +1111
-
文件file1在工作目录中已经修改,但是并没有暂存,因此可以直接使用git diff进行比较,此时比较的就是工作目录和索引的差异。
如果想要将工作目录与索引或版本库进行比较:
- $ git diff --cached
-
- $ git diff HEAD
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- diff --git a/file1 b/file1
- index 8baef1b..5f2f16b 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -abc
- +1111
-
可以看出,索引和版本库是没有差异的,而工作目录和版本库是存在差异的,这里的差异打印和之前使用git diff的打印是相同的。
- $ git add file1
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
-
- $ echo 2222 > file1
此时再进行比较:
- $ git diff
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- diff --git a/file1 b/file1
- index 5f2f16b..c7dc989 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -1111
- +2222
-
- $ git diff HEAD
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- diff --git a/file1 b/file1
- index 8baef1b..c7dc989 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -abc
- +2222
-
- $ git diff --cached
- diff --git a/file1 b/file1
- index 8baef1b..5f2f16b 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -abc
- +1111
这里将file1暂存,同时在工作目录修改了file1的内容,这里的工作目录,索引,版本库的内容彼此之间都是不同的,因此会有上面的比较。
这里将file1提交:
- $ git commit file1 -m "commit file1 again"
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- [master 3fc324d] commit file1 again
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
- $ git status
- On branch master
- nothing to commit, working tree clean
-
- $ cat file1
- 2222
-
- $ git diff HEAD HEAD^1
- diff --git a/file1 b/file1
- index c7dc989..8baef1b 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -2222
- +abc
这里可以看出,提交之后HEAD和HEAD^存在差异。
git命令支持两个点..来显示两个提交之间的差异,即以下两条命令是等同的:
- git diff commit1..commit2
-
- git diff commit1 commit2
而在git log命令中,两点..是用来显示整个提交范围内的历史记录的,这是两者的差异之处。也可以看出:
通常情况下,git diff会基于从给定树对象的根开始的整个目录结构。然而,可以使用和git log中相同的路径限制来限制git diff只输出版本库的一个子集。
- $ echo 1111 > file1
-
- $ echo 2222 > file2
-
- $ git diff
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- warning: LF will be replaced by CRLF in file2.
- The file will have its original line endings in your working directory
- diff --git a/file1 b/file1
- index 8baef1b..5f2f16b 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -abc
- +1111
- diff --git a/file2 b/file2
- index acbe86c..c7dc989 100644
- --- a/file2
- +++ b/file2
- @@ -1 +1 @@
- -abcd
- +2222
-
- $ git diff file1
- warning: LF will be replaced by CRLF in file1.
- The file will have its original line endings in your working directory
- diff --git a/file1 b/file1
- index 8baef1b..5f2f16b 100644
- --- a/file1
- +++ b/file1
- @@ -1 +1 @@
- -abc
- +1111
比如上面的例子,如果同时修改了file1,file2,而在当前状态下只需要考虑file1的提交,那么就可以使用git diff file1来限制比较的对象只为file1。