【问题标题】:Do squashed commits conflict with their original commits压扁的提交是否与其原始提交发生冲突
【发布时间】:2016-04-02 14:22:58
【问题描述】:

以下场景是否会产生需要手动解决的冲突?

  1. 您为 PR 提交了一个功能分支,其中包含提交 D、E。

  2. 在审查 PR 时,您继续在本地处理相同的功能分支,并添加更多提交 F、G、H。

  3. 在某个时候,PR 被批准并合并到 master。 Commits D/E on master have been replaced with commit X due to squashing。您现在有一个包含提交 D、E、F、G、H 的本地分支和一个包含提交 X 的主分支。

  4. 您希望将提交 F/G/H 合并到 master。因此,您尝试将本地分支(包含 D/E/F/G/H)合并到 master(包含 X)中。

提交 D/E 和 X 涉及完全相同的代码行,但具有不同的提交 ID。如果将 D/E 放在一起看并与 X 比较,它们是相同的。但是如果把 D 单独看和 X 相比,它们之间有很多不同,在通常修改的行上。

git 是否足够聪明地合并 {D/E - X} 而没有任何合并冲突?或者上面会产生一些需要人工干预的冲突吗?

【问题讨论】:

  • 你为什么不试试?

标签: git git-merge merge-conflict-resolution


【解决方案1】:

我在本地运行了一些 git 实验,复制了问题中描述的工作流程步骤。不幸的是,答案似乎是肯定的。使用 git squash 会导致很多合并冲突,如果你不是很小心你在做什么。

我已经在this blog post 中广泛地写过这个。


如果您在没有任何压缩的情况下进行了简单的合并,就不会发生上述问题。在这种情况下,合并后,master 和您的本地分支都将包含提交 D-E。因此,下次您尝试合并本地 D-E-F-G-H 分支时,git 会简单地通过在 master 之上应用 F-G-H 来执行合并。

然而,因为我们做了壁球,这最终让 git 感到困惑。它不是简单地在 X 上应用 F-G-H,而是尝试将 D-E-F-G-H 与 X 合并在一起。不幸的是,由于提交 F-G-H 修改了同样被 X 修改的代码行,因此产生的差异因合并冲突而失败。

解决此问题的一些潜在方法:

  1. 蛮力:收拾它并手动解决所有冲突。

  2. 提交拉取请求后,请勿在拉取请求中包含的提交之上开发任何其他提交。从 git 的角度来看,pull-request 中的那些提交将会消失,所以你不想依赖它们。不幸的是,这意味着您想要在刚刚提交的内容之上进行任何改进,都需要等到您的拉取请求被批准和合并。

  3. 如果您在较早的拉取请求之上进行了改进,请不要合并较早的拉取请求。相反,使用更新的分支提交新的拉取请求,或者用您所做的所有改进覆盖现有的拉取请求。不幸的是,这使得拉取请求过程成为一个全有或全无的事情。理想情况下,您可能希望逐步批准/合并初始拉取请求和其他改进。相反,为了防止冲突,您必须强迫自己一次合并整个事物,或者根本不合并任何事物。

  4. 假设您之前的 PR 已合并,并且您现在也想合并到 master 中。与其尝试将整个分支合并到 master 中,不如挑选您创建的增量提交,并仅合并那些挑选的提交。所以在上面给出的例子中,cherry pick 提交 F-G-H,而不是尝试将 D-E-F-G-H 合并到 X 中,将它们应用到 X 之上,然后使用生成的分支创建一个拉取请求,而不是尝试将 D-E-F-G-H 合并到 X 中。这很好用,避免了所有冲突,并允许您在任何您想要的时间/节奏上完成您的开发工作。不幸的是,这还需要您手动跟踪 D-E == X 的事实,并且稍后提交 F-G-H 需要手动挑选和应用。这需要您付出更多的时间和认知努力,并且通过挑选过多的提交(并且无论如何都会产生冲突)或挑选过少的提交(并且错过重要的更改)也很容易搞砸这一步。

  5. 避免使用 github 的 squash-on-megre 功能。在提交拉取请求之前,要么在本地压缩所有提交。或者合并拉取请求而不进行任何压缩。这是大多数项目的现状,以及随之而来的所有好处/缺点。

如您所见,在合并之前压缩所有提交存在一个真正的问题/成本,并且上述解决方案都不是完美的。我不确定以上哪一个是最不邪恶的。但我确实想鼓励您更深入地思考这个问题,并意识到利用这个很棒的 GitHub 新功能所涉及的注意事项。

【讨论】:

  • 导致问题的不是壁球“合并”本身,而是根本没有合并的事实。一旦你的新工作被合并,你必须将你的D-E-F-G-H 序列变基为一个F'-G'-H' 序列,其父序列(即F' 的父序列)是新的X 提交。这很烦人,但可行。 (这不是 github 特有的,而是 git 的一般原则:merge 使用 merge base 来计算差异,而 squash “合并”根本不合并,因此不影响合并基地。)
  • 我同意。您所描述的在概念上类似于上面的建议 #4:手动选择您想要的提交,并将它们应用于新分支。就像你提到的,这是可行的,但不幸的是,开发人员现在需要解析他的 git 日志并开始寻找他感兴趣的特定 git-commits。
【解决方案2】:

Git 比较自共享基础以来每个提示的变化。相同的更改不会导致冲突。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-02
    • 2017-04-02
    • 2019-01-21
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 2020-03-12
    相关资源
    最近更新 更多