git显示合并提交

问题描述 投票:22回答:2

当我有一个合并提交并运行git show #commit时,它只显示提交日志,而不是实际更改的差异,如

commit c0f50178901e09a1237f7b9d9173ec5d1c4936c
Merge: ed234b ded051
Author: abc
Date:   Mon Nov 21 15:56:33 2016 -0800

    Merge branch 'abc'

我理解真正的提交是在合并日志中,但我想保存输入,有没有办法在一个显示差异?

git merge show
2个回答
74
投票

TL; DR:使用git show -m c05f017git show --first-parent c05f017,或者git diff c05f017^ c05f017


你的问题有一个根本性的错误:提交不是差异;提交是快照。这似乎是一种没有区别的区别 - 对于某些提交,它是。但对于合并提交,它不是。

git show(或git log -p)将提交显示为diff时,它通过将提交的快照与其他内容进行比较来实现。 git diff命令执行相同的操作:它将一个提交与另一个提交进行比较。 (或者它可以将提交与工作树,或索引的内容或其他一些组合进行比较。)

对于普通提交,很明显要比较什么:将此提交的快照与之前(即父级)提交的快照进行比较。这就是git show所做的(以及git log -p):它从父提交运行git diff到此提交。

但是,合并提交不只有一个父提交。他们有两个parent.1。这就是他们首先“合并提交”的原因:合并提交的定义是一个至少有两个父项的提交。


1A合并提交可以有三个或更多父母。这些被称为“章鱼合并”。但是,他们没有做任何特别的事情,主要是为了炫耀。 :-)你可以在这里忽略它们。


When there are two parents, which one(s) should git show compare against?

git log -p默认选择做的是根本不进行比较。你可以通过添加各种标志来显示它(见下文)。

git show默认选择做什么更复杂。由于有两个父母,git show首先与“第一个父母”进行比较,然后比较第二个父母。然后 - 这部分非常关键 - 它结合了两个差异,产生了所谓的“组合差异”。

对于下一节,让我注意一个棘手但非常有用的Git语法。如果您有像c05f017这样的提交ID,则可以在此之后添加插入符号或“帽子”字符^,以命名父提交。您可以选择添加另一个数字来选择哪个父项。对于常规(非合并)提交,只有一个,所以c05f017^是父。对于合并提交,c05f017^c05f017^1都表示第一个父级,而c05f017^2表示第二个父级。


2我把它放在引号中,因为第一个父母的想法在Git中特别重要,我们稍后会看到。换句话说,Git最关心哪个父母是第一个,而其余的只是“其余的”。


Combined diffs

组合的diff格式在the documentation中描述,但是关键位首先被描述为here,以使其特别模糊:3

请注意,组合差异仅列出从所有父项修改的文件。

也就是说,假设M是合并提交,并且差异M ^ 1对M表示文件mainline.txtcommon.txt都被更改。进一步假设差异M ^ 2和M表示文件sidebranch.txtcommon.txt都被改变了。组合差异将仅显示common.txt,跳过mainline.txtsidebranch.txt,因为这两个文件仅从一个父母(每个)修改。 (即便如此,Git可能只显示common.txt的一些差异。)


3我花了很长时间才在文档中找到这个,因为我一直在看另一部分。


Splitting the diffs

-m选项-m可能代表合并在这里 - 告诉Git,实际上,“拆分”合并。也就是说,不是试图将每个父对象的差异组合成一个大的组合差异,而是仅针对每个父对象显示差异,一次显示一个差异。

这有时是你想要的。当它不是你想要的时候,你可以运行你自己的显式git diff来区分两个父母中的一个(或见下文)。

Which parent should you diff against?

通常,正确的答案是“第一个父母”。

“第一个父”概念的关键是当Git进行合并提交时,它总是记录您当时所在的分支,作为第一个父级。另一个分支成为第二个父母。

也就是说,如果你在develop并且你合并了topic

$ git checkout develop
$ git merge topic

Git将在你当前的分支develop上创建一个新的提交 - 一个合并提交,有两个父母。合并提交的第一个父级将是刚才develop的提示。第二个父母将是(仍然)topic的提示。

由于您通常关注合并带来的内容,因此与第一个父母进行比较会给您这一点。所以通常这就是你想要的。因此,git show允许您运行git show --first-parent。那“分裂”提交然后git show只对第一个父进行差异。 (这与git show -m略有不同,git log -p --first-parent将提交分成两次:第一次拆分与第一次父级进行比较,第二次拆分与第二次父级进行比较。)

类似地,您可以运行-m ...但是您仍然必须添加git log以将更改视为补丁,因为默认情况下--first-parent只是跳过显示完全合并的差异。 (在内部,跳过因为合并操作会覆盖拆分使其行为像非合并的方式。)这里,mentioned here标志具有更重要的效果:日志操作不会查看任何侧分支的提交,只有那些主(第一 - 父)行。


0
投票

作为git diff --cc $M $M^1 $M^2 $(git merge-base $M^1 $M^2) ,这些解决方案涉及显示组合差异,如:

diff --cc

但是:当合并涉及重命名时,“git diff --cc --combined-all-paths $M $M^1 $M^2 $(git merge-base $M^1 $M^2) ”的输出没有显示原始路径。 Git 2.22(2019年第一季度)中的新选项将原始树中的路径添加到输出中。

log

diff-tree--combined-all-paths:添加::100644 100644 100644 fabadb8 cc95eb0 4866510 MM describe.c ::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM bar.sh ::100644 100644 100644 e07d6c5 9042e82 ee91881 RR phooey.c 选项

即使重命名或复制检测处于活动状态,合并的合并diff格式也只会列出一个文件名。

例如,使用原始格式可能会看到:

bar.sh

这不会让我们知道phooey.c的原始名称在第一个父母身上是什么,并且不让我们知道--combined-all-paths的任何一个原始名字在父母中的任何一个。

相反,对于非合并提交,原始格式确实提供原始文件名(以及重命名分数以引导)。 为了还为合并提交提供原始文件名,添加一个-c选项(必须与--cc::100644 100644 100644 fabadb8 cc95eb0 4866510 MM desc.c desc.c desc.c ::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM foo.sh bar.sh bar.sh ::100644 100644 100644 e07d6c5 9042e82 ee91881 RR fooey.c fuey.c phooey.c 一起使用,并且可能仅在重命名或复制检测处于活动状态时有用),以便我们可以在重命名时打印制表符分隔的文件名。参与其中。

这会将上面的输出转换为:

--- a/phooey.c
+++ b/phooey.c

此外,在补丁格式中,这会更改from / to标头,以便不是只有一个“from”标头,而是为每个父标记获得一个。 例如,而不是拥有

--- a/fooey.c
--- a/fuey.c
+++ b/phooey.c

我们会看到

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.