“git show”不会返回与“git diff”相同的结果

时间:2014-08-15 11:04:39

标签: git

我在git存储库中有一个提交,其中git show表示只修改了一个文件,而git diff显示两个文件被修改。

我创建了一个展示相同行为的简单示例存储库。

在样本回购中,我们有这个简单的历史记录:

*   c248261      (HEAD, origin/master, master) Merged feature into master.
|\  
| * d23c497      (feature) Modified fileA and fileB in feature.
* | 06a7f5e      Modified fileA and fileC in master.
* |   9cd1a6e    Merged feature into master.
|\ \  
| |/  
| * aed2e5e      Modified fileA and fileB in feature.
* | c6e4fe7      Mofified fileC in master.
* |   19ed298    Merged feature to master.
|\ \  
| |/  
| * c0f2abc      Added fileB and modified fileA in feature.
* | 47c67cf      Added fileC in master.
|/  
* 56a9b73        Added fileA in master.

当我查看提交c248261时,例如SourceTree,我可以看到fileAfileB已被修改。使用git diff会得到相同的结果:

$ git diff --name-only c248261^..c248261
fileA
fileB
$

或使用速记符号:

$ git diff --name-only c248261^!
fileA
fileB
$

当我尝试使用git show获取相同信息时,只显示两个文件中的一个:

$ git show --name-only c248261
commit c2482616b6b6781d0580ec1008ef7d0ab5f73a70
Merge: 06a7f5e d23c497
Author: ...
Date:   Fri Aug 15 16:19:02 2014 +0200

    Merged feature into master.

fileA
$

同样,git diff-tree没有显示任何内容:

$ git diff-tree c248261
$

有人可以解释这个区别吗?

我正在使用git版本2.0.4。

3 个答案:

答案 0 :(得分:2)

什么是git show

命令git show是一个通用命令,用于在git中显示有关对象的信息。

从手册页(git help show):

Shows one or more objects (blobs, trees, tags and commits).
...
For commits it shows the log message and textual diff.
It also presents the merge commit in a special format as produced by
  git diff-tree --cc
...

因此,git show的输出不同,因为这是 merge 提交而不是 plain 提交。

git diff-tree --cc的手册页说:

--cc
    This flag changes the way a merge commit patch is displayed, in a 
    similar way to the -c option. It implies the -c and -p options and
    further compresses the patch output by omitting uninteresting hunks whose
    the contents in the parents have only two variants and the merge result
    picks one of them without modification. When all hunks are uninteresting,
    the commit itself and the commit log message is not shown, just like in
    any other "empty diff" case.

进一步

-c
    This flag changes the way a merge commit is displayed (which means
    it is useful only when the command is given one <tree-ish>, or
    --stdin). It shows the differences from each of the parents to the
    merge result simultaneously instead of showing pairwise diff
    between a parent and the result one at a time (which is what the -m
    option does). Furthermore, it lists only files which were modified
    from all parents.

请注意我在此重复的最后一行:

Furthermore, it lists only files which were modified from all parents.

因此,合并提交中的git show将仅列出在将提交与所有父项合并进行比较时修改的文件。对于普通合并(即2个父母),这正是合并的文件。例如,如果您执行此合并:

git checkout master
git merge feature

git show列出的文件是合并前在 masterfeature中修改的文件,并在合并提交中合并在一起

对于章鱼合并 - 即两个以上的父母 - 生成的文件必须与所有父母中的文件不同,才能由git show显示。

请注意,在合并提交中使用git show时,其他文件也会显示。例如,如果您调用git merge --no-commit然后在提交之前执行以下任何操作,则git show上的这些文件也将显示在合并提交中:

  • 添加新文件。
  • 删除现有文件。
  • 修改任何文件 - 包括已由git merge暂存的任何文件。

结论

git show正在做的是显示所谓的组合差异

在合并提交上运行命令git show的结果可以被认为是仅显示已合并的文件,而不是仅显示从两个父项之一中保持不变的文件。

这有点令人惊讶,因为许多人希望看到哪些文件与您刚刚合并的分支相比被修改了。

那么如果你想看看父母之间的差异怎么办?

让我们最后看一下git show的手册页:

COMBINED DIFF FORMAT
  Any diff-generating command can take the `-c` or --cc option to produce
  a combined diff when showing a merge. This is the default format when
  showing merges with git-diff(1) or git-show(1). Note also that you can
  give the `-m' option to any of these commands to force generation of
  diffs with individual parents of a merge.

因此我们可以使用-m选项来获取这两个差异:

git show -m commit

这将逐一为你提供所有父母的差异。

要查看合并提交与您合并到的分支上的上一次提交(即第一个父级)之间的区别,请使用以下任一命令:

git show --first-parent commit
git diff commit^..commit
git diff commit^!

--first-parent选项确实属于git log,但也适用于git show。表示法commit^!commit^..commit的简写。

要查看合并提交与您合并的分支之间的区别(例如,查看您从其他分支中遗漏的内容),请使用

git diff commit^2..commit

符号commit^2表示commit的第二个父级。

如果您有超过2个父母(即章鱼合并),我相信您可以猜测如何区分第3,第4等提交。

答案 1 :(得分:0)

通过查看提交c248261的提交消息,可能提交您正在寻找的是合并提交。合并提交有多个父母。

  
    

修订参数的后缀^表示该提交对象的第一个父级。

  

所以,当你说,

$ git diff --name-only c248261^..c248261
fileA
fileB
$

它从提交c248261的第一个父项执行差异。

你可以试试,

$ git diff --name-only c248261^2..c248261

将为您提供以下结果,

fileA
--other files if exist--

在两个父母合并之后,会创建一个新的提交,即c248261,它只有一个差异文件,这就是你所说的,

git show --name-only c248261

答案 2 :(得分:0)

从手册页(git help show

For commits it shows the log message and textual diff.
It also presents the merge commit in a special format as produced by
  git diff-tree --cc
...
For plain blobs, it shows the plain contents.

因此,git show的输出不同,因为这是合并提交而不是普通blob。 git diff-tree --cc的文档说:

--cc
    This flag changes the way a merge commit patch is displayed, in a 
    similar way to the -c option. It implies the -c and -p options and
    further compresses the patch output by omitting uninteresting hunks whose
    the contents in the parents have only two variants and the merge result
    picks one of them without modification. When all hunks are uninteresting,
    the commit itself and the commit log message is not shown, just like in
    any other "empty diff" case.