version-control - 为什么一个分支中的 Mercurial 退出会影响其他分支?

标签 version-control mercurial branch dvcs three-way-merge

这是一个很难解释的情况,所以请耐心等待。我有一个 Mercurial 存储库,有 2 个主要分支,default 和 dev。

工作通常在 dev 的命名分支(功能分支)中完成。任何时候都可能有许多特征分支。一旦该分支中的工作完成,它就会 merge 回 dev。

当准备发布时,会从 dev(发布分支)创建另一个命名分支。有时有必要从版本中排除整个功能。如果是这种情况,则功能分支 merge 到 dev 的 merge 变更集将从新的发布分支中退出。

一旦发布分支准备好发布,它就会 merge 到默认值中(因此默认值始终代表生产中代码的状态)。开发分支和功能分支上的工作照常进行。

当需要发布另一个版本时会出现问题,包括在前一个版本中退出的功能。一个新的发布分支正常创建(脱离开发)。这个新的发布分支现在包含从前一个发布分支回退的功能(因为回退是在发布分支上执行的,并且 merge 变更集保留在开发分支上)。

这一次,当发布分支准备发布并 merge 到默认值时,由于先前发布分支中的 merge 回退而回退的任何更改都不会 merge 到默认值中。为什么会这样?由于新的发布分支包含所有功能分支变更集(没有任何内容被撤消),为什么默认分支也没有收到所有这些变更集?

如果以上所有内容都难以理解,这里是 TortoiseHg 的屏幕截图,显示了基本问题。 “branch1”和“branch2”是特性分支,“release”和“release2”是发布分支:

enter image description here

最佳答案

我相信问题在于 merge 的工作方式与您想象的不同。你写

Since the new release branch contains all of the feature branch changesets (nothing has been backed out), why does the default branch not receive all of these changesets too?



当您 merge 两个分支时,将其视为将一个分支的所有更改应用到另一个分支是错误的。所以default分支不会“接收”来自 release2 的任何变更集.我知道这就是我们通常对 merge 的看法,但这是不准确的。

merge 两个变更集时真正发生的事情如下:
  • Mercurial 找到两个变更集的共同祖先。
  • 对于两个变更集之间不同的每个文件,Mercurial 运行 three-way merge algorithm使用祖先文件、第一个变更集中的文件和第二个变更集中的文件。

  • 在您的情况下,您正在 merge 修订版 11 和 12。最不常见的祖先是修订版 8。这意味着 Mercurial 将在来自修订版的文件之间运行三路 merge :
  • 修订版 8:不退订
  • 修订版 11:功能分支已退出
  • 修订版 12:不退订

  • 在三向 merge 中,变化总是胜过没有变化。 Mercurial 发现文件在 8 和 11 之间发生了变化,而在 8 和 12 之间没有变化。因此它在 merge 中使用修订版 11 的更改版本。这适用于任何三路 merge 算法。完整的 merge 表如下所示,其中 old , new , ... 是三个文件中匹配大块的内容:
    ancestor  local  other -> merge
    old       old    old      old (nobody changed the hunk)
    old       old    new      new (they changed the hunk)
    old       new    old      new (you changed the hunk)
    old       new    new      new (hunk was cherry picked onto both branches)
    old       foo    bar      <!> (conflict, both changed hunk but differently)
    

    恐怕是merge changeset shouldn't be backed out完全是因为这种令人惊讶的 merge 行为。如果您尝试取消 merge ,Mercurial 2.0 及更高版本将中止并提示。

    一般来说,可以说三路 merge 算法假设一切都好 .所以如果你 merge branch1进入 dev然后稍后用回退撤消 merge ,然后 merge 算法会认为状态比以前“更好”。这意味着您不能只是重新 merge branch1进入 dev在稍后获取回退的更改。

    您可以做的是在 merge 到 default 时使用“虚拟 merge ”。 .您只需 merge 并始终保留要 merge 到的发布分支中的更改 default :
    $ hg update default
    $ hg merge release2 --tool internal:other -y
    $ hg revert --all --rev release2
    $ hg commit -m "Release 2 is the new default"
    

    这将回避问题并强制default就像release2 .这假设绝对没有对 default 进行任何更改。无需 merge 到发布分支中。

    如果您必须能够发布具有跳过功能的版本,那么“正确”的方法是根本不 merge 这些功能。 merge 是一个强有力的 promise :您告诉 Mercurial, merge 变更集现在拥有来自其祖先的所有好东西。只要 Mercurial 不让您使用 pick your own base revision when merging ,三向 merge 算法不会让您改变对退出的看法。

    但是,您可以做的是撤销撤销。这意味着您将功能分支中的更改重新引入到发布分支。所以你从一个图表开始
    release: ... o --- o --- m1 --- m2
                            /      /
    feature-A:   ... o --- o      /
                                 /
    feature-B:  ... o --- o --- o 
    

    您现在确定 A 功能不好,并取消了 merge :
    release: ... o --- o --- m1 --- m2 --- b1
                            /      /
    feature-A:   ... o --- o      /
                                 /
    feature-B:  ... o --- o --- o 
    

    然后您将另一个功能 merge 到您的发布分支中:
    release: ... o --- o --- m1 --- m2 --- b1 --- m3
                            /      /             /
    feature-A:   ... o --- o      /             /
                                 /             /
    feature-B:  ... o --- o --- o             /
                                             /
    feature-C:  ... o --- o --- o --- o --- o 
    

    如果你现在想重新引入 A 特性,那么你可以退出 b1 :
    release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
                            /      /             /
    feature-A:   ... o --- o      /             /
                                 /             /
    feature-B:  ... o --- o --- o             /
                                             /
    feature-C:  ... o --- o --- o --- o --- o 
    

    我们可以将增量添加到图表中,以更好地显示何时何地发生了什么变化:
                         +A     +B     -A     +C     --A
    release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
    

    在第二次退出后,您可以再次与 feature-A merge 。如果在那里添加了新的变更集。您要 merge 的图形如下所示:
    release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
                            /      /             /
    feature-A:   ... o -- a1 - a2 /             /
                                 /             /
    feature-B:  ... o --- o --- o             /
                                             /
    feature-C:  ... o --- o --- o --- o --- o 
    

    然后你 merge a2b2 .共同的祖先将是 a1 .这意味着在三向 merge 中您需要考虑的唯一更改是 a1 之间的更改。和 a2a1b2 .这里b2已经在“中”进行了大量更改 a2所以 merge 会很小。

    关于version-control - 为什么一个分支中的 Mercurial 退出会影响其他分支?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9500399/

    相关文章:

    mercurial - 撤消 Mercurial 推送

    configuration - 中止 : no username supplied (see "hg help config")

    version-control - Mercurial:从 HG 存储库中永久删除敏感数据?

    svn - 从特定的主干修订版在 Subversion 中创建分支

    mercurial - 如何在 Mercurial 中为非提示修订创建分支?

    windows - 如何在 Hg 中同时处理默认和分支?

    java - 在我们的工作环境中使用 GIT 的最佳方式是什么?

    gradle - 在哪里放置我不想提交版本控制的 build.gradle 行?

    sql-server - SQL Server Management Studio 2005 和源代码管理

    git push failed - unpack-objects异常退出