Git中的合并是对称的吗?

Posted

技术标签:

【中文标题】Git中的合并是对称的吗?【英文标题】:Are merges in Git symmetric? 【发布时间】:2012-08-24 22:11:30 【问题描述】:

假设我们有两个分支(BC),它们与共同的祖先 A 不同。从 B 合并到 C 会产生与从 C 合并到 B 相同的结果吗?

  A
  |
 / \
B   C

澄清一下-我假设任何手动合并冲突解决方案都会在两个方向上发生。但是发生的任何自动合并会导致选择相同的代码吗?这是我的假设,因为提交日期在两个方向上都是相同的。

进一步澄清 - 我知道实际的合并会根据方向产生彼此的“镜像”。我只是询问自动解决的冲突。

【问题讨论】:

在相关说明中,您可能会从 Git 邮件列表中找到这个已有三年历史的线程,它涉及 Git 记录合并的方式如何对合并的“方向”敏感: thread.gmane.org/gmane.comp.version-control.git/127361 有人知道@seh 提供的链接的缓存版本吗?该页面似乎已关闭/消失。 哎哟。我今天晚上做了一些搜索,但仍然找不到可行的链接。 【参考方案1】:

默认合并的答案是肯定的。三路合并找到一个共同的祖先,然后应用双方的差异,这是一个不依赖于顺序的操作。合并排序和交换性的话题在git list 上引发了一场引人入胜的讨论(如果你喜欢这种事情,那就是)。注意B into CC into B 应该是对称的,但(B into C) into AB into (C into A) 不一定是对称的。

[编辑说明,2020 年 4 月:如果您添加 -X ours-X theirs 之类的选项,答案将变为“否”,请参阅 twalberg's answer 和其他人以了解更多注意事项。]


更详细一点,根据下面文斯的评论和 seh 对问题的评论,B into CC into B 之间会有两个明显的区别,这两者都不会影响问题中引用的自动合并解决方案。

首先,历史会有所不同。合并提交的父级将根据合并顺序而改变。对于这些示例,我将使用“first_branch”和“second_branch”,因此我可以保留字母来表示提交。

git checkout first_branch && git merge second_branch

E <- merge commit
|\
| D <- second_branch's tip
| |
| C <- another commit on second_branch 
| |
| B <- and another
|/
A <- first_branch's tip before the merge

在这种情况下,E 的“第一个父级”E^1 是合并前 first_branch 的提示。 second_branch 是合并提交的“第二个父级”,又名E^2。现在考虑反过来:

git checkout second_branch && git merge first_branch

E <- merge commit
|\
| D <- first_branch's tip
| |
| C <- another commit on first_branch 
| |
| B <- and another
|/
A <- second_branch's tip before the merge

父母颠倒了。 E^1 是合并前 second_branch 的尖端。 E^2 是 first_branch 的尖端。

其次,冲突的显示顺序会颠倒。在第一种情况下,冲突可能如下所示:

<<<<<<< HEAD
This line was added from the first_branch branch.
=======
This line was added from the second_branch branch.
>>>>>>> second_branch

在第二种情况下,相同的冲突如下所示:

<<<<<<< HEAD
This line was added from the second_branch branch.
=======
This line was added from the first_branch branch.
>>>>>>> first_branch

这些差异都不会影响自动合并解析,但是当您颠倒三向合并顺序时它们会出现。

【讨论】:

如果你测试过,你介意提供一个简短的例子吗?我的意思是我很好奇,如果你只是合并而不提供任何合并策略/选项,而是强制自动合并(如果可能的话),如果一行发生冲突怎么办?你会有:&lt;&lt;&lt;&lt;&lt;&lt;&lt; yours:sample.txt Conflict resolution is hard; let's go shopping. ======= Git makes conflict resolution easy. &gt;&gt;&gt;&gt;&gt;&gt;&gt; theirs:sample.txt?或者你会选择其中一个,哪一个? @Vince 顺序对历史和这些冲突的呈现方式很重要,但自动合并解决结果将是相同的。我编辑了更多细节和一些例子。 Hamano 在此答案中链接到的讨论中的帖子是必读的thread.gmane.org/gmane.comp.version-control.git/107737/… - 虽然不确定它是否提供了问题的答案 @Mr_and_Mrs_D 死链接 :( 所以 git-merge 是可交换的(直到历史元数据和合并冲突解决)。为什么它不具有关联性?【参考方案2】:

内容是对称的,但是如果你使用 GitHub 或 Bitbucket 或者你喜欢的本地 Git 查看器查看合并时所做的更改,你会发现合并提交中列出的文件更改是不同的。 (以及上面提到的其他事情。)

git checkout b
git merge c

合并中显示的文件更改将是自 bc 分歧以来对 c 所做的更改。

git checkout c
git merge b

合并中显示的文件更改将是自bc 分歧以来对b 所做的更改。

【讨论】:

【参考方案3】:

这取决于您所说的“相同结果”是什么意思。从内容的角度来看,假设不存在冲突,或者所有存在的冲突都以完全相同的方式精心解决,则生成的新合并提交的内容应该是相同的。

但是,从历史拓扑的角度来看,两者是非常不同的。如果您在分支 B 上并在 C 中合并,则 B 的 HEAD 将移动以指向合并提交,但 C 保持原位。相反,如果您在 C 上并在 B 中合并,则 C 的 HEAD 移动,而 B 保持在原处。所以最终的拓扑是非常不同的,这对任何一个分支的未来开发都有影响,即使新提交的内容在任何一种情况下都是相同的。

【讨论】:

【参考方案4】:

不,我认为它不会是对称的。首先,您可以设置合并策略选项,特别是在您的情况下,theirsours 将决定选择 B 还是 C。

在自动合并中,我认为例如,如果您要合并到您的远程分支,则远程分支优先于您的更改,因此这意味着从 B 调用 git merge C 将导致选择 C ​​更改。不过我不是 100% 确定,所以您可以自己尝试并告诉我们。

【讨论】:

设置策略选项的命令:git merge -s&lt;strategy&gt; -X&lt;option&gt; 一些参考页面:kernel.org/pub/software/scm/git/docs/git-merge.html

以上是关于Git中的合并是对称的吗?的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud-分布式配置中心加密-对称加密

针对对称邻接矩阵优化 Floyd-Warshall

技术 | RSA非对称加密算法详解

对称加密与分对称加密的实现

密码学中的对称加密和非对称加密

非对称加密中的公钥和私钥怎么来的