Git show vs Git log --numstat输出差异

时间:2016-05-04 19:20:57

标签: git

我将git show和git log与相同的选项进行比较。我在不同的提交上得到了不同的结果。我还没有真正挖掘过文档但还没弄清楚为什么会这样,但是我猜它与每个命令如何解释修订列表以及提交图形是什么有关?例如,关于FFmpeg的演示:

案例1 git log:

> git log -n1 --numstat --format='%H' 00049f193d07cec0409069bc51d0dcb8ab9da837
00049f193d07cec0409069bc51d0dcb8ab9da837

案例1 git show:

> git show -n1 --numstat --format='%H' 00049f193d07cec0409069bc51d0dcb8ab9da837
00049f193d07cec0409069bc51d0dcb8ab9da837

4       0       libavcodec/mpegaudiodecheader.c

案例2 git log:

> git log -n1 --numstat --format='%H' 001d668d40b5f87d19271c7d5521368b5187425b
001d668d40b5f87d19271c7d5521368b5187425b

2       5       libavformat/dvenc.c
2       6       libavformat/gxfenc.c
5       0       libavformat/internal.h
2       5       libavformat/movenc.c
2       5       libavformat/mxfenc.c
7       0       libavformat/utils.c

案例2 git show:

> git show -n1 --numstat --format='%H' 001d668d40b5f87d19271c7d5521368b5187425b
001d668d40b5f87d19271c7d5521368b5187425b

2       5       libavformat/dvenc.c
2       6       libavformat/gxfenc.c
5       0       libavformat/internal.h
2       5       libavformat/movenc.c
2       5       libavformat/mxfenc.c
7       0       libavformat/utils.c

基本上,我很困惑为什么对于案例1,日志省略了更改的文件(libavcodec/mpegaudiodecheader.c),而show包含它们,然后在案例2中,输出是相同的。

供参考:

> git diff --numstat 00049f193d07cec0409069bc51d0dcb8ab9da837 00049f193d07cec0409069bc51d0dcb8ab9da837^
0       4       libavcodec/mpegaudiodecheader.c

2 个答案:

答案 0 :(得分:4)

Joseph K. Strauss's answer是正确的(这是合并提交)但不完全。缺少的信息分散在Git文档和源代码中,这就是为什么它们很难找到的原因。

首先,00049f193d07cec0409069bc51d0dcb8ab9da837 really is a merge commit。它的两个父母是d832020bd853f84b96a3fdf3e0a385d8492ec8c8fcbcc561e0fdc95a7dd48b92db53846726aec27e(我们不需要知道它们的确切数字,但也可以记录它们以显示它的“合并”)。

The git show documentation给了我们一个提示:

  

任何差异生成命令都可以在显示合并时使用-c--cc选项生成组合差异。显示与git-diff(1)git-show(1)的合并时,这是默认格式。另请注意,您可以为这些命令中的任何一个提供-m选项,以强制使用合并的单个父项生成差异。

这里缺少的是-c--cc本身的说明,这两个链接的手册页中都找不到,但 中的git diff-tree。然而,在我们去那里之前,值得前往the git diff documentation,我们在那里找到:

  

“git-diff-tree”,“git-diff-files”和“git-diff --raw”可以使用-c--cc选项为合并提交生成diff输出。 [剪辑示例]
  请注意,组合差异仅列出从所有父级修改过的文件。

(粗体我的,但它确实非常重要;我们会在片刻再次看到它,我将再次使用粗体)。现在我们可以跳回git diff-tree,在那里我们找到-c--cc的实际说明:

  

-c
  此标志更改了合并提交的显示方式(这意味着仅当命令被赋予一个 tree-ish --stdin时才有用)。它同时显示了每个父项与合并结果的差异,而不是一次显示父项和结果之间的成对差异(这是-m选项的作用)。此外,它列出了仅从所有父母修改的文件

     

--cc
  此标志以与-c选项类似的方式更改合并提交修补程序的显示方式。它意味着-c-p选项,并通过省略不感兴趣的帅哥进一步压缩补丁输出,其中父母的内容只有两个变体,合并结果选择其中一个而不进行修改。当所有的人都不感兴趣时​​,提交本身和提交日志消息不会显示,就像在任何其他“空差异”情况下一样。

请注意,这告诉我们--ccgit show的默认值,但对git log没有任何说明。事实证明git log默认只是完全抑制合并差异输出,而git show设置--cc。前者似乎没有在任何地方记录,但可以在Git源代码中找到builtin/log.crevision.c

[revision.c]
void init_revisions(struct rev_info *revs, const char *prefix)
{
        memset(revs, 0, sizeof(*revs));

        revs->abbrev = DEFAULT_ABBREV;
        revs->ignore_merges = 1;
        revs->simplify_history = 1;
[snip]

这为所有命令设置忽略合并(revs->ignore_merges = 1)的默认操作;想要处理合并的命令需要清除标志(这也在Documentation/technical/api-revision-walking.txt中注明)。

git showgit log(以及其他几个)都在builtin/log.c中实现,其中包含以下内容:

static void log_setup_revisions_tweak(struct rev_info *rev,
                                      struct setup_revision_opt *opt)
{
        if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
            rev->prune_data.nr == 1)
                DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);

        /* Turn --cc/-c into -p --cc/-c when -p was not given */
        if (!rev->diffopt.output_format && rev->combine_merges)
                rev->diffopt.output_format = DIFF_FORMAT_PATCH;

        /* Turn -m on when --cc/-c was given */
        if (rev->combine_merges)
                rev->ignore_merges = 0;
}

这是组合差异选项(如果选中)启用显示合并的位置。同时,git show

static void show_setup_revisions_tweak(struct rev_info *rev,
                                       struct setup_revision_opt *opt)
{
        if (rev->ignore_merges) {
                /* There was no "-m" on the command line */
                rev->ignore_merges = 0;
                if (!rev->first_parent_only && !rev->combine_merges) {
                        /* No "--first-parent", "-c", or "--cc" */
                        rev->combine_merges = 1;
                        rev->dense_combined_merges = 1;
                }
        }
        if (!rev->diffopt.output_format)
                rev->diffopt.output_format = DIFF_FORMAT_PATCH;
}

因此git show会检查是否指定了-m。如果没有,则会在内部启用-m,然后启用--cc,除非有三个明确选项中的任何一个:-c--cc--first-parent。前两个有意义(不要覆盖用户的设置),但第三个只是奇怪。 (例如,如果我们去做一个组合差异,但只是在一个父ID中被拉出来,也许以后可以避免引起问题。)

仍然不是很明显的是为什么这些不同:

$ git log --no-walk --numstat 00049f193d07cec0409069bc51d0dcb8ab9da837 
[snip output: log message, with no diff-stats]
$ git show --numstat 00049f193d07cec0409069bc51d0dcb8ab9da837
[snip log message]
4       0       libavcodec/mpegaudiodecheader.c

如果我们只是将-m添加到git log(以便我们清除rev->ignore_merges标志),我们就会得到针对父母的numstat差异。但是,如果我们添加--cc,我们会得到与git show相同的结果:

$ git log -m --cc --no-walk --numstat 00049f193d07cec0409069bc51d0dcb8ab9da837
[snip log message]
4       0       libavcodec/mpegaudiodecheader.c

并且有点想法现在清楚地说明为什么我们只看到一个文件:它是唯一一个来自父母双方都有变化的文件。这是相同的约束对于任何组合差异,当然,将--cc替换为-c(使用相同的git log)会产生相同的结果。

底线,因为它是

如果没有-m-c--ccgit log会打印合并的日志消息,但甚至不会尝试向其父级显示合并提交的差异。如果没有这些选项,git show会设置--cc。这大约有一半记录在案。

答案 1 :(得分:1)

看起来您的第一次提交(00049f193d07cec0409069bc51d0dcb8ab9da837)是合并。因此,它将假设您不关心查看提交的统计信息,但show将显示第一个父项的差异的numstat。

我试图找到这方面的文档,但我不能。