我可以在Mercurial分支和合并方面做得比我目前做得更好,还是可以做得比在此示例测试用例中更好?

时间:2012-11-20 21:11:52

标签: mercurial branching-and-merging

在商业开发的版本控制中,通常有多个项目分支。在我的mercurial-managed项目中,我经常有一个stable和trunk版本,它来自一些普通的父类,如下所示:

      V8     (the parent of both V8-stable and V9, revisions 1..100)
       |
       +---  V8_stable  (bug fix branch, revisions 101 to 500 )
       |
       +---  V9_trunk   (trunk, revisions 501 to 1000 )

项目的所有上述版本都有一个文件,我们称之为helloworldapp.py。这些示例是Python中的,因为它是我所知道的最类似伪代码的语言,但问题不是Python问题。现在,在mercurial中,您可以使用克隆进行分支,或者您可以使用Mercurial的内置分支功能。在这个例子中,我使用整个存储库的克隆进行分支。

这是V8 helloworldapp.py,它是共同的父版本:

# helloworldapp.py rev 100 (v8)
def func1(a,b,c,d,e):
    print "stuff"
def func2(a,b,c,d,e):
    func1(a,b,c,d,e)
def func3(a,b,c,d,e):
    func2(a,b,c,d,e)
def func4(a,b,c,d,e):
    func3(a,b,c,d,e)
def func5(a,b,c,d,e):
    func4(a,b,c,d,e)
def func6(a,b,c,d,e):
    func5(a,b,c,d,e)
def func7(a,b,c,d,e):
    func6(a,b,c,d,e)

func7(1,2,3,4,5)

以下是修订版500,V8稳定分支的一部分:

# helloworldapp.py rev 500 (v8_stable)
def func1(a,b,c,d,e):
    print "stuff"

def morestuff():
   print "morestuff"

morestuff()
func1(1,2,3,4,5)

这是V9中继分支的修订版1000部分:

# helloworldapp.py rev 1000 (v9_trunk)
def func1(a,b,c,d,e):
    print "stuff"

def func4(a,b,c,d,e):
    morestuff()
    morestuff()
    morestuff()
    func1(a,b,c,d,e)

def morestuff():
   print "hello"

func4(1,2,3,4,5)

以上文件是一个非常简短的例子,说明当分支不同步时,在面向文件的版本控制中发生的情况,当我必须管理“稳定到主干”合并时,这会导致我的困难(通过拉动然后合并)。

这是您在合并时最终会遇到的情况。请注意,在现实世界中,问题通常会放大100倍到1000倍左右。我常常遇到5000多行Hg合并无法解决的冲突,数百个文件需要我在KDiff3中手动合并每个冲突。

除了不让分支永远不同步之外,Mercurial用户可以做些什么来使这种情况下的合并更容易?在我上面说明的情况中,“在文件的分支A上的第6行工作”与“在文件的分支B上的第6行工作”相同,并且逐行合并创建合并冲突,其中两个用户实际上(在他们自己的脑海中)在文件中的不同功能上工作。通过从一个文件中删除不再使用的函数的行为,因为不再需要它,您现在几乎可以确保更多的合并冲突机会。您几乎必须制定诸如“永远不会在上游稳定分支中移动或删除行”的规则。我知道,如果您使用的是基于Smalltalk图像的版本控制系统,那么“它上面的线路”的意外将不再进入。如果Mercurial使用的diff工具理解Python,它可以在Python代码上做得更好,但代价是它可能在C#代码上完全不能正常工作。因此,这是基于文件的编程和DVCS工具的最新技术。细

所以,在这里合并的情况下,

enter image description here

click here for larger version

* 我看到的是合并冲突,我希望它可以弄清楚我要么全部要么不想要“morestuff”函数:

enter image description here

我希望得到(自动):

enter image description here

我在bitbucket上发布了样本存储库:     helloworldapp_v9     helloworldapp_v8_stable

尝试这个“最简单的例子,我可以构建当你试图解决合并冲突时会发生什么”,克隆上面的一个,然后从另一个拉,然后合并。最后我的问题是:Mercurial的专业用户如何应对这种情况?理解这个例子是人为的,但是展示了DVCS工具用户遇到的一些复杂性,但在现实世界中,这些冲突往往比我在这里展示的简单案例复杂得多。我已经学会了使用TortoiseHG和KDIFF3快速处理大多数小而简单的冲突,但我发现merge-hell比我记得使用Subversion或Perforce更不是问题,但我仍然不认为(a)程序员(我)或(b)我的工具已经完成了所有可以帮助管理和理解这种复杂性的工具。我觉得存在使用Mercurial的替代解决方案和工具以及工作策略,我还没有尝试或了解过。也许MQ和Rebase?

1 个答案:

答案 0 :(得分:3)

实际上,根据我的经验,现实世界通常看起来并不是这样,原因有两个:

  1. 我们更频繁地合并(在您的示例中从v8到v9),以便Mercurial逐步了解两个分支之间的组合方式。五个变更集是一步一步拼凑出来的很多变化(我之前已经这样做了!)。

  2. 合并我们的分支时,我们的更改不会像您的示例那样残酷地发生冲突。通过减少碰撞和每次更改的更多上下文,合并工具可以更好地将它们组合在一起。

  3. 我们确实有碰撞,需要弄清楚如何手动将它们组合在一起,如果我们把它推迟,这可能会让人头疼。但是,一旦我们这样做,共同的祖先现在就是合并,我们不需要再次重新审视这种碰撞。通过更频繁地合并,您可以减少自共同祖先以来的变更集数量。

    我有兴趣通过定期从V8_stable合并到V9_trunk来重新运行您的示例。如果你在函数defs之间添加一些文本以给hg更多的上下文来分离变化,我也会感兴趣。


    尝试与您的示例尝试更频繁的合并后,它的效果不佳。如果你的版本差异很大(只有15%-25%相同),它们将成为根本不同的代码库,并且合并不再有意义。那时,我试图将这些碎片分解成单独的文件,以允许两个版本(和我的理智!)和平共存。