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

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

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

> https://github.com/martingd/git-show-vs-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,我可以看到fileA和fileB被修改了.使用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.

最佳答案 什么是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的输出是不同的,因为这是一个合并提交而不是一个普通的提交.

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列出的文件是在合并之前在master和feature中都被修改的文件,并在合并提交中合并在一起.

对于章鱼合并 – 即两个以上的父母 – 结果文件必须与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.表示法提交^!是提交^ ..提交的简写.

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

git diff commit^2..commit

符号提交^ 2表示提交的第二个父级.

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

点赞