凌云的博客

行胜于言

跟我一起学Git (六) 差异

分类:Git| 发布时间:2014-03-11 22:10:35


git diff命令的格式

你可以对三种tree或tree-like的对象使用git diff

  • 任意提交中的任意tree对象
  • 你的工作目录
  • index

git diff的例子

$ git diff

这个命令会比较工作目录和index

$ git diff commit

这种格式的命令会比较工作目录和给定的 commit

$ git diff --cached commit

这种格式的命令会比较index和给定的 commit 如果没有提供 commit 那么比较 index 和 HEAD

$ git diff commit1 commit2

这个格式的命令比较两个任意的提交,这两个提交甚至可以在不同分支中

git diff常用选项

git diff命令除了这些基本的形式外还有很多不同的选项,下面列出一些比较常用的:

  • --M 这个选项会检查重命名
  • -w 或着 --ignore-all-space 这两个选项在比较的时候会忽略空格
  • --stat 这个选项会输出比较的统计信息(多少行改变了,多少行增加了,多少行删除了)
  • --color 这个选项会将不同的差异类型用不同的颜色输出

git diff和提交区间

还有两种形式的git diff命令需要说明,特别是和git log 作比较

在下面的例子中,有两点是需要注意的:

  • git diff 不会关系它比较的文件的历史和分支的
  • git log会非常关心文件是如何从一个版本变成另一个版本的, 也就是说一个分支是什么时候分出去的以及在每个分支中发生了什么

例子:

git diff commit1..commit2

在这个例子中,git log master..maint 表示五个单独的提交V,W,...,Z 而 git diff master..maint表示H和Z的差别, 也就是11个提交的增量:C,D,...,H和V,...,Z 。

git diff commit1...commit2

git diff commit1...commit2 表示 commit1 和 commti2 的共同祖先(merge base)之间的差别 git log master...maint 表示 C,D,...,H和 V,...,Z git diff master...maint 表示 Z和V的差别,也就是 V, W,...,Z 的增量差异

对git diff使用路径限制

和git log类似,也可以对 git diff 使用路径限制,只显示特定路径下的文件的变化

例子:

$ git diff --stat master~5 master
Documentation/git-add.txt            |    2 +-
Documentation/git-cherry.txt         |    6 +++++
Documentation/git-commit-tree.txt    |    2 +-
Documentation/git-format-patch.txt   |    2 +-
Documentation/git-gc.txt             |    2 +-
Documentation/git-gui.txt            |    4 +-
Documentation/git-ls-files.txt       |    2 +-
Documentation/git-pack-objects.txt   |    2 +-
Documentation/git-pack-redundant.txt |    2 +-
Documentation/git-prune-packed.txt   |    2 +-
Documentation/git-prune.txt          |    2 +-
Documentation/git-read-tree.txt      |    2 +-
Documentation/git-remote.txt         |    2 +-
Documentation/git-repack.txt         |    2 +-
Documentation/git-rm.txt             |    2 +-
Documentation/git-status.txt         |    2 +-
Documentation/git-update-index.txt   |    2 +-
Documentation/git-var.txt            |    2 +-
Documentation/gitk.txt               |    2 +-
builtin-checkout.c                   |    7 ++++-
builtin-fetch.c                      |    6 ++--
git-bisect.sh                        |   29 ++++++++++++--------------
t/t5518-fetch-exit-status.sh         |   37 ++++++++++++++++++++++++++++++++++
23 files changed, 83 insertions(+), 40 deletions(-)

我们可以限制它,使得只显示 Documentation 的变化

$ git diff --stat master~5 master Documentation
Documentation/git-add.txt            |    2 +-
Documentation/git-cherry.txt         |    6 ++++++
Documentation/git-commit-tree.txt    |    2 +-
Documentation/git-format-patch.txt   |    2 +-
Documentation/git-gc.txt             |    2 +-
Documentation/git-gui.txt            |    4 ++--
Documentation/git-ls-files.txt       |    2 +-
Documentation/git-pack-objects.txt   |    2 +-
Documentation/git-pack-redundant.txt |    2 +-
Documentation/git-prune-packed.txt   |    2 +-
Documentation/git-prune.txt          |    2 +-
Documentation/git-read-tree.txt      |    2 +-
Documentation/git-remote.txt         |    2 +-
Documentation/git-repack.txt         |    2 +-
Documentation/git-rm.txt             |    2 +-
Documentation/git-status.txt         |    2 +-
Documentation/git-update-index.txt   |    2 +-
Documentation/git-var.txt            |    2 +-
Documentation/gitk.txt               |    2 +-
19 files changed, 25 insertions(+), 19 deletions(-)

当然,你也可以只显示单个文件的变化

$ git diff master~5 master Documentation/git-add.txt
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index bb4abe2..1afd0c6 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -246,7 +246,7 @@ characters that need C-quoting.  `core.quotepath`
configuration can be used to work this limitation around to some degree,
but backslash, double-quote and control characters will still have problems.
-See Also
+SEE ALSO
--------
linkgit:git-status[1]
linkgit:git-rm[1]

也可以通过-S"string"参数查找含有特定字符串的变化集

$ git diff -S"octopus" master~50
diff --git a/Documentation/RelNotes-1.5.5.3.txt b/Documentation/RelNotes-1.5.5.3.txt
new file mode 100644
index 0000000..f22f98b
--- /dev/null
+++ b/Documentation/RelNotes-1.5.5.3.txt
@@ -0,0 +1,12 @@
+GIT v1.5.5.3 Release Notes
+==========================
+
+Fixes since v1.5.5.2
+--------------------
+
+ * "git send-email --compose" did not notice that non-ascii contents
+   needed some MIME magic.
+
+ * "git fast-export" did not export octopus merges correctly.
+
+Also comes with various documentation updates.

比较Subversion的差异和Git的派生差异

其他的版本管理系统,比如 CVS 和 Subversion 会追踪文件的变化然后保存文件的不同版本的差异集。 这种技术用于减少需要的磁盘空间。但是缺点是在这种系统的内部需要大量时间来处理如 “版本A和版本B之间进行了哪些修改”这类的事情, 比如有一个文件在当前工作目录的版本是 r1095 但是版本库的版本已经是 r1123 那么当你的Subversion客户端从版本库更新这个文件的时候Subversion需要 找出这个文件从 r1095 到 r1123 的差异并将这些差异合并成一个大的差异然后返回给 你的 Subversion 客户端,最后你的客户端再对这个文件应用这个差异。

而在Git中不一样,每个提交都包含一颗树:用于列出这个提交包含的文件。 每棵树都是独立的,也就是说对于每个文件的不同版本Git都会保留这个文件的所有内容。 当然Git也会有diff和patch的概念, 但对Git来说这些都不是基本的数据类型而是派生的数据类型。 如果你查看.git目录, 你不会发现任何差异文件, 而在Subversion仓库中,你会发现大量差异文件。

就像 Subversion 可以获得 r1095 和 r1123 的完整差异集, Git也可以获得任意两个状态的差异集。 但是Subversion必须查找 r1095 到 r1123 之间所有的版本, Git不用关心这些中间的步骤。