在Mercurial上支持向后合并

时间:2008-11-05 17:25:11

标签: mercurial merge dvcs branch

如何在没有死亡的情况下扭转合并对极化分支的影响?

这个问题困扰着我几个月,我终于放弃了。

您有1个存储库,其中包含2个命名分支。 A和B.

A发生的变化将不可避免地发生在B.

B上直接发生的变化绝不会发生在A上。

在这样的配置中,将“B”合并为“A”会在存储库中产生严重问题,因为对B的所有更改都显示在A中,就像它们是在A中一样。

从这种情况中恢复的唯一“正常”方式似乎是“退出”合并,即:

 hg up -r A 
 hg backout -r BadMergeRev --parent BadMergerevBeforeOnA 

看起来很好,花花公子,直到你决定稍后在正确的方向合并,然后你最终会发生各种令人讨厌的事情,并且在特定分支B上删除/注释掉的代码突然变得没有注意或没有注释。

到目前为止,还没有一个可行的可行解决方案,除了“让它做它的事情,然后解决所有问题”,说实话有点尴尬。

这是澄清问题的图片:

[原始图片丢失]

档案C& E(或更改C& E)必须仅出现在分支b上,而不是出现在分支a上。 这里的版本A9(分支a,revno 9)是问题的开始。

修订版A10和A11是“退出合并”和“合并退出”阶段。

修订版B12是多变的,错误地反复删除了意图不被删除的更改。

这种困境引起了很多挫折和蓝烟,我想结束它。

注意

尝试禁止反向合并可能是一个明显的答案,无论是使用钩子还是使用策略,我发现将其解除的可能性相当高,并且发生这种情况的可能性很大,即使采取对策,你必须仍然认为不可避免地会发生 ,以便你可以解决它。

精心制作

在模型中我使用了Seperate文件。这些使问题听起来很简单。这些仅代表任意更改,它们可以是一个单独的行。

另外,为了增加对伤害的侮辱,分支A上发生了实质性的变化,留下了常见的问题“分支A的变化与分支B的变化发生冲突,分支B刚刚出现(并且已退出)比如分支A的变化而不是“

关于历史重写技巧:

所有这些追溯活动解决方案的问题如下:

  1. 我们有9000次提交。
  2. 新鲜克隆需要半小时
  3. 如果存在甚至一个错误的存储库某处的克隆,那么就会有一种与原始存储库联系回来的可能性,并将其全部敲打再次。
  4. 每个人都已经克隆了这个存储库,现在已经过了几天,正在进行提交。
  5. 一个这样的克隆,恰好是一个实时网站,所以“擦掉那一个并从头开始”=“大nono”
  6. (我承认,上面的许多内容都有些愚蠢,但它们不受我的控制)。

    唯一可行的解​​决方案是假设人们可以做错所有事情,并且有一种方法可以“撤消”这种错误。

5 个答案:

答案 0 :(得分:50)

我认为我找到了一个永久修复错误合并的解决方案,并且不需要您手动检查任何差异。诀窍在于回溯历史并生成与不良合并并行的提交。

因此,我们拥有一个存储库,每个维护版本的单个产品都有单独的分支。与问题中提出的情况一样,在早期版本的分支上进行的所有更改(即该版本中的错误修正)都必须最终合并到更高版本的分支。

具体而言,如果在BRANCH_V8上签入了某些内容,则必须将其合并到BRANCH_V9。

现在其中一个开发人员犯了以下错误:他将BRANCH_V9中的所有更改合并到BRANCH_V8中(即合并方向错误)。此外,在糟糕的合并之后,他会在注意到他的错误之前执行一些额外的提交。

所以情况如下图所示。

o  BRANCH_V8 - 13 - important commit right after the bad merge
|
o    BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|\
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8 (ie. last known good state)
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

我们可以按如下方式解决这个错误:

  1. 将您的本地目录更新为BRANCH_V8的最后状态:hg update 11
  2. 创建最后一个良好状态的新子项:
    1. 更改某个文件$EDITOR some/file.txt(这是必要的,因为Mercurial不允许空提交)
    2. 提交这些更改hg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"
      现在的情况如下:
      o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      |
      | o  BRANCH_V8 - 13 - important commit right after the bad merge
      | |
      | o  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |/|
      o |  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      | o  BRANCH_V9 - 10 - last commit on BRANCH_V9
      
  3. 将新生成的头部与发生错误合并的修订版合并,并在提交之前丢弃所有更改。 不要简单地合并两个头,因为你将失去合并后发生的重要提交!

    1. 合并:hg merge 12(忽略任何冲突)
    2. 丢掉所有更改:hg revert -a --no-backup -r 14
    3. 提交更改:hg commit -m "throwing away wrong merge from BRANCH_V9" 现在看起来像是:
      o    BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      |\
      | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | |
      +---o  BRANCH_V8 - 13 - important commit right after the bad merge
      | |
      o |  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |\|
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      
    4. IE中。 BRANCH_V8上有两个头:一个包含坏合并的修复,另一个包含BRANCH_V8上的剩余重要提交,它发生在合并之后。

    5. 在BRANCH_V8上合并两个头:
      1. 合并:hg merge
      2. 提交:hg commit -m "merged two heads used to revert from bad merge"
    6. BRANCH_V8最终的情况现在已得到纠正,如下所示:

      o    BRANCH_V8 - 16 - merged two heads used to revert from bad merge
      |\
      | o    BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      | |\
      | | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | | |
      o | |  BRANCH_V8 - 13 - important commit right after the bad merge
      |/ /
      o |  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |\|
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      

      现在BRANCH_V8的情况是正确的。剩下的唯一问题是从BRANCH_V8到BRANCH_V9的下一次合并将是不正确的,因为它将在错误合并的“修复”中合并,这是我们在BRANCH_V9上不需要的。这里的技巧是在单独的更改中从BRANCH_V8合并到BRANCH_V9:

      • 首次合并,从BRANCH_V8到BRANCH_V9,BRANCH_V8在合并错误之前的正确更改。
      • 合并错误及其修复中的第二次合并,并且无需检查任何内容,丢弃所有更改
      • 第三次合并BRANCH_V8的其余更改。

      详细说明:

      1. 将您的工作目录切换为BRANCH_V9:hg update BRANCH_V9
      2. 合并BRANCH_V8的最后一个良好状态(即您生成的用于修复错误合并的提交)。这种合并是像任何常规合并一样的合并,即。冲突应该像往常一样解决,不需要抛弃任何东西。
        1. 合并:hg merge 14
        2. 提交:hg commit -m "Merging in last good state of BRANCH_V8" 现在的情况是:
          @    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
          |\
          | | o    BRANCH_V8 - 16 - merged two heads used to revert from bad merge
          | | |\
          | +---o  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
          | | | |
          | o | |  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
          | | | |
          | | o |  BRANCH_V8 - 13 - important commit right after the bad merge
          | | |/
          +---o  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
          | |/
          | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
          | |
          o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
          | |
          
      3. 在BRANCH_V8及其修复程序中合并错误合并,并丢弃所有更改:
        1. 合并:hg merge 15
        2. 还原所有更改:hg revert -a --no-backup -r 17
        3. 提交合并:hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away" 现在的情况 :
          @    BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away
          |\
          | o    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
          | |\
          +-----o  BRANCH_V8 - 16 - merged two heads used to revert from bad merge
          | | | |
          o---+ |  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
          | | | |
          | | o |  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
          | | | |
          +-----o  BRANCH_V8 - 13 - important commit right after the bad merge
          | | |
          o---+  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
          |/ /
          | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
          | |
          o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
          | |
          
      4. 合并来自BRANCH_V8的剩余更改:
        1. 合并:hg merge BRANCH_V8
        2. 提交:hg commit -m "merging changes from BRANCH_V8"
      5. 最终情况如下:

        @    BRANCH_V9 - 19 - merging changes from BRANCH_V8
        |\
        | o    BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away
        | |\
        | | o    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
        | | |\
        o | | |  BRANCH_V8 - 16 - merged two heads used to revert from bad merge
        |\| | |
        | o---+  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
        | | | |
        | | | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
        | | | |
        o | | |  BRANCH_V8 - 13 - important commit right after the bad merge
        |/ / /
        o---+  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
        |/ /
        | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
        | |
        o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
        | |
        

        在所有这些步骤之后,您不必手动检查任何差异,BRANCH_V8和BRANCH_V9是正确的,未来从BRANCH_V8到BRANCH_V9的合并也将是正确的。

答案 1 :(得分:2)

在紧要关头,您可以将存储库导出到一堆差异,编辑历史记录,然后将您想要的内容粘合到一个新的存储库中,这样就不会有损坏的风险。对你的例子来说可能不是太糟糕,但我不知道真实的历史是什么样的。

我在执行更简单的操作时引用了此页面:

http://strongdynamic.blogspot.com/2007/08/expunging-problem-file-from-mercurial.html

答案 2 :(得分:2)

好的,首先在与破坏的存储库(hg init)不同的目录中创建一个新的存储库。现在,将最后一个已知的好版本添加到新存储库中;确保拉出错误合并,然后拉出所有内容。在旧存储库中,更新到上一个已知良好版本的A,并执行以下操作:

hg graft r1 r2 r3

其中r1-3是在拙劣合并之后所做的更改。你可能会在这一点上遇到冲突;解决它们。

这应该针对上一个已知良好版本的A 产生新的更改。将这些新更改提取到新存储库中。只是为了仔细检查你没有错过任何东西,做一个针对旧存储库的hg传入。如果你看到除了拙劣的合并和r1-3以外的任何东西,请拉它。

扔掉旧存储库。你完成了。合并根本不在新的存储库中,您永远不必重写历史记录。

答案 3 :(得分:1)

所以你想把B中的一些变更集合并成A?像你一直在做的更改集是一个非常糟糕的主意,因为你已经受苦了。

您应该使用移植扩展,或者使用第三个分支进行常规更改以合并到A和B中。

答案 4 :(得分:1)

经过与freenode上#mercurial的一些有用的人讨论后,mpm提供了一个部分解决方案,似乎适用于我的测试用例(我生成了一个假存储库,试图复制方案)

然而,在我的实际存储库中,由于我不太了解的原因,它仍然不完美。

以下是目前提出的解决此问题的方法的图表:

[原始图片丢失]

现在要修复的问题,但我仍然需要比较差异(即:b46:b11 vs b46:b8,a43:a10 vs a43:a9)并手动编辑一些变化回来了。

在我获得适用于任何存储库的保证方式之前,不要关闭此问题/接受答案。

重要

任何尝试这种东西的人都应该克隆他们的存储库,然后像沙盒一样玩它。正如您应该使用任何合并过程一样,因为如果出现错误,您可以将其丢弃并重新开始。