Joseph K. Strauss的回答是正确的(这是一个合并提交),但不够完整。缺少的信息散布在Git文档和源代码中,这就是为什么它们很难找到的原因。
首先,00049f193d07cec0409069bc51d0dcb8ab9da837
确实是一个合并提交。它的两个父节点分别是d832020bd853f84b96a3fdf3e0a385d8492ec8c8
和fcbcc561e0fdc95a7dd48b92db53846726aec27e
(我们不需要知道它们的确切编号,但也可以记录下来以显示其“合并性”)。
git show
文档给了我们一个提示:
任何生成差异的命令都可以使用-c
或--cc
选项,在显示合并时生成组合差异。这是使用git-diff(1)或git-show(1)显示合并时的默认格式。还要注意,您可以给这些命令之一加上-m
选项,以强制生成与合并的各个父节点不同的差异。
这里缺少的是对-c
和--cc
本身的描述,在这两个链接的手册页面中都找不到,但在git diff-tree
的手册中可以找到。然而,在我们去那里之前,值得先去git diff
文档,在那里我们发现了这个:
"git-diff-tree"、"git-diff-files"和"git-diff --raw"可以使用-c
或--cc
选项,为合并提交生成差异输出。[删节示例]
请注意,组合差异仅列出从所有父级修改的文件。
(这里我加粗了一下,因为它非常重要;我们马上就会再次看到它,在那里我还会使用加粗。)现在我们可以跳回到
git diff-tree
,在那里我们找到了
-c
和
--cc
的实际描述:
-c
此标志更改合并提交的显示方式(这意味着只有在命令给出一个 tree-ish 或--stdin
时才有用)。 它同时显示每个父节点与合并结果之间的差异,而不是一次显示父节点和结果之间的成对差异(这是-m
选项执行的操作)。 此外,它仅列出从所有父节点修改的文件。
--cc
此标志更改合并提交补丁的显示方式,类似于-c
选项。 它意味着-c
和-p
选项,并通过省略在父节点中其内容仅有两种变体且合并结果选择其中一个而没有进行修改的不相关段来进一步压缩补丁输出。 当所有段都不相关时,提交本身和提交日志消息将不显示,就像在任何其他“空差异”情况下一样。
请注意,这告诉我们--cc
是git show
的默认设置,但没有提到git log
。事实证明,git log
默认只抑制合并差异输出,而git show
设置了--cc
。前者似乎没有在任何地方记录,但可以在Git源代码中的builtin / log.c和< b>revision.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 show
和
git 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) {
rev->ignore_merges = 0;
if (!rev->first_parent_only && !rev->combine_merges) {
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
,然后除非有三个显式选项之一:
-c
、
--cc
和
--first-parent
,否则打开
--cc
。前两个选项很有道理(不要覆盖用户的设置),但第三个选项很奇怪。(也许这是为了避免后面出现问题,例如我们进行联合差异比较,但只引入了一个父级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
如果我们在
git log
命令中加入
-m
选项(以清除
rev->ignore_merges
标志),则可以获得针对两个父提交的numstat差异。 如果我们此外再加上
--cc
,那么我们将得到与
git show
相同的结果:
$ git log -m --cc --no-walk --numstat 00049f193d07cec0409069bc51d0dcb8ab9da837
[snip log message]
4 0 libavcodec/mpegaudiodecheader.c
稍加思考,现在清楚为什么我们只看到一个文件:它是唯一一个来自两个父版本都有变化的文件。这与任何合并差异的约束条件相同,并且确实,用相同的
git log
将
--cc
替换为
-c
会产生相同的结果。
底线就是,如果没有
-m
、
-c
或
--cc
,
git log
会打印合并的日志消息,但从不尝试显示合并提交与其父版本之间的差异。如果没有这些选项中的任何一个,
git show
将设置
--cc
。这大约只有一半文档说明了。
git show
仅显示“所有父级中修改的文件”(与使用-c或--cc的git log相同)?再次查看第1种情况(合并提交)的提交,根据我的测试,似乎git show
和git log -c/--cc
(如Joseph K Strauss的答案所述)仅显示第一个父级的numstat/diff。 - Mikelog
没有任何标志,根本不会显示任何差异,即使使用了--numstat
。) - torekgit show -c <commit>
和git show -c --numstat <commit>
是不一致的。第一个父级有8行添加/13行删除的差异,而第二个父级在audiothing.c中有4行添加的差异(每个父级修改不同的行)。git show -c
显示组合差异,但添加--numstat
使它看起来只有4行的差异(这就是为什么我认为它正在查看第一个父级)。在这种情况下,我期望+12/-13。 - Mike