【问题标题】:Git Merging - what happens to 2 branches being merged at same timeGit合并-同时合并2个分支会发生什么
【发布时间】:2018-03-28 04:02:22
【问题描述】:

我对在git上合并有一个不清楚的理解,我想正确理解。

假设我在 master 分支上有一个文件 F,它已经有 100 个 LOC。我从 master 创建了一个分支 A,我写了 50 LOC,从第 101 行开始到第 150 行。我创建了一个合并请求以将分支 A 合并到 master。所以如果分支 A 将被合并,那么 master 上的文件 F 将有 150 LOC

让我们假设分支 A 还没有合并到 master,还在等待。我从master创建了一个新的分支B。我还写了 50 LOC,也从第 101 行开始到第 150 行(因为分支 A 尚未合并)。我还为分支 B 创建了一个 MR

如果 2 个人审查 2 个 MR 会发生什么,并且:

  1. 他们同时合并 2 个 MR? master会不会有冲突,因为两个分支都想合并到第101到150行?

  2. 如果先合并分支A,说明master已经有150个LOC,但分支B还是从第101行开始到第150行,因为它是从master创建的,当时它还有100个LOC。 B合并的时候会不会也有冲突?或者 Git 如何处理这些?

提前致谢(我不是巨魔,只是想弄清楚一些东西,以防有人会举报这个问题)

【问题讨论】:

    标签: git merge gitlab branch git-branch


    【解决方案1】:

    我认为需要澄清一点:冲突和合并策略是 git 本身的概念。 “合并请求”,OTOH,是 gitlab 的一个概念(其他 repo 主机也有类似的概念),但对 git 本身毫无意义。你的问题最好通过谈论 git 来回答;所以我们只需要知道合并请求是一个可以在 git 中启动合并操作的工作流。因此,让我们将您的问题分为两部分:

    顺序合并

    简答:可能会有冲突。

    是否会有冲突取决于合并策略。我的测试表明通常会有冲突,因为 git 在第 101 - 150 行中看到了替代更改。由于两组更改都是添加的,我想您可以设想添加两组行而不会发生冲突 - 尽管不清楚它们的顺序是什么会进去。你可以让 git 尝试使用 union 合并驱动程序来做到这一点;见http://kernel.org/pub/software/scm/git/docs/gitattributes.html

    您可以通过命令行参数告诉 git 以不同的方式解决合并问题,但由于这些指示将适用于整个提交 - 而不仅仅是设置此条件的一个文件 - 您通常不希望这样做。您可以使用.gitattributes 来影响 git 如何仅合并一个文件,前提是您可以提前知道该方法何时适用于(整个)文件。

    因此,对于如何更改 merge 的行为,有很多选择 - 在不知道具体期望结果的情况下,此处无法详细说明。但根据我的经验,通常使用默认的合并设置并在发生冲突时解决它们会很好。

    并发合并

    实际上不可能在一个 repo 中“同时”发生两个合并。如果主机提供了某种方式来直接在托管 (origin) 存储库上开始合并——我实际上不知道有人这样做,但为了争论——那么一个合并必须首先完成,并且其他人会将合并的结果视为起点;所以请参阅答案的前一部分。

    可能发生的情况是,一个人可以在一个 repo 上执行一次合并,另一个人可以在第二个 repo 上执行另一次合并,然后当他们都尝试与远程同步时可能会发生冲突。这可能是这样的:

    (请注意,在整个示例中,我假设 true 合并 - 即如果您使用 no-ff 选项会发生什么。合并图可能更简单,但结果将是就冲突而言,如果允许快进合并,则相同。)

    所以回购开始于

                B <--(branch_B)
               /
    x -- x -- O <--(master)
               \
                A <--(branch_A)
    

    所有提交都包含一个文件。在O 中,该文件有 100 行。 AB 分别在文件末尾添加 50 行。

    现在 Alice 合并 branch_A 和 Bob 合并 branch_B,每个都在他们的本地 repo 中。所以爱丽丝有

                B <--(branch_B)
               /
    x -- x -- O -- MA <--(master)
               \  /
                A
                ^-(branch_A)
    

    鲍勃有

                v-(branch_B)
                B
               /  \
    x -- x -- O -- MB <--(master)
               \       
                A <--(branch_A)
    

    为了分享他们的工作,他们将各自尝试pushorigin;就像merges 一样,一个人会在另一个人开始之前先完成,即使他们试图在同一时刻开始推送。

    所以 Alice 得到了她的推送,origin 被更新为看起来就像她的本地人一样。当 Bob 尝试推送时,他收到一个错误,因为他的 masterorigin 上的 master 后面(或者,我们可以说,在更新后,在 origin/master 后面,假设是典型的映射)。

    所以 Bob 必须先pull(或fetchmerge)才能push。为了更清楚地说明,让我们假设他fetches。现在他有

           v-(branch_B)
                B
               /  \
    x -- x -- O -- MB <--(master)
              |\
              | MA <--(origin/master)
              |/
              A <--(branch_A)
    

    为了完成pull 的效果,他需要将origin/master 合并到master - 所以即使这种情况归结为首先涵盖的“顺序合并”场景。实际上,如果您使用快进合并跟踪相同的场景,很明显,如果所有操作都由一个用户在一个 repo 中完成,则此处所需的“第二次合并”与“第二次合并”完全相同。

    【讨论】:

    • 感谢您的详细回答:)
    猜你喜欢
    • 2017-02-12
    • 1970-01-01
    • 2015-07-19
    • 2016-04-14
    • 2011-03-25
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 2022-01-05
    相关资源
    最近更新 更多