git显示合并提交

Soh*_*qui 30 git merge show

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

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

    Merge branch 'abc'
Run Code Online (Sandbox Code Playgroud)

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

tor*_*rek 84

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从父提交运行到此提交.

但是,合并提交不只有一个父提交.他们有两个父母.1 这首先使它们成为"合并提交":合并提交的定义是一个至少有两个父项的提交.


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


当有两个父母时,哪一个应该git show比较?

什么git log -p选择默认做的不是在所有比较.你可以通过添加各种标志来显示它(见下文).

什么git show选择默认做的是更加复杂.由于有两个父母,git show首先比较针对"第一个亲本",2随后比较靠在第二个亲本.然后 - 这部分非常关键 - 它结合了两个差异,产生了所谓的"组合差异".

对于下一节,让我注意一个棘手但非常有用的Git语法.如果您有一个提交ID c05f017,则可以在此之后添加插入符号或"帽子"字符^,以命名父提交.您可以选择添加另一个数字来选择哪个父项.对于常规(非合并)款只有一个有,那么c05f017^父.对于合并提交,c05f017^c05f017^1都意味着第一父,同时c05f017^2意味着第二父.


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


组合差异

文档中描述了组合的diff格式,但这里首先描述一个关键位,以使其特别模糊:3

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

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


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


拆分差异

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

这有时是你想要的.当它不是你想要的时候,你可以运行你自己的显式git diff来对两个父母之一进行差异(或者见下文).

你应该反对哪一个家长?

通常,正确的答案是"第一个父母".

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

也就是说,如果您正在进行develop并且您合并topic:

$ git checkout develop
$ git merge topic
Run Code Online (Sandbox Code Playgroud)

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标志具有更重要的影响:日志操作不会查看任何侧分支的提交根本只有主(第一 - 父)线上的那些.

  • 谢谢,帮助找到了在解决的冲突中丢失的方法。我认为 `git show -m c05f017` 是最有用的。使用 `git show -m -p --stat c05f017` 将添加已更改文件的列表。如果你跳过 `-p` 你只会得到文件列表。 (3认同)
  • 谢谢。`git show HEAD^2` 很有帮助,而且在解释后容易记住。很遗憾`git show --first-parent` 做了同样的事情...... (2认同)

Kay*_*y V 8

这是一个简单的命令:

git show HEAD -m

考虑到它反映了其他常用命令,也许它更容易记住。

它显示了合并后对合并分支所做的所有更改。


Von*_*onC 5

如此处所述,这些解决方案涉及显示组合差异,例如:

git diff --cc $M $M^1 $M^2 $(git merge-base $M^1 $M^2)
Run Code Online (Sandbox Code Playgroud)

但是:diff --cc合并涉及重命名时,“ ”的输出没有显示原始路径 。
Git 2.22(2019 年第一季度)中的一个新选项将原始树中的路径添加到输出中。

git diff --cc --combined-all-paths $M $M^1 $M^2 $(git merge-base $M^1 $M^2)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这不会让我们知道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
Run Code Online (Sandbox Code Playgroud)

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

--- a/phooey.c
+++ b/phooey.c
Run Code Online (Sandbox Code Playgroud)

我们会看到

--- a/fooey.c
--- a/fuey.c
+++ b/phooey.c
Run Code Online (Sandbox Code Playgroud)