如何用mercurial管理并发开发?

时间:2010-09-15 15:10:56

标签: mercurial workflow dvcs mercurial-queue

这是一个最佳实践问题,我希望答案是“它取决于”。我只是希望了解更多真实世界的场景和工作流程。

首先,我在谈论同一个项目的不同变化,所以请不要再做任何改动。

假设您在hg存储库中拥有代码库。您开始处理复杂的新功能A,然后您的可信测试人员报告了一个复杂的错误B(您有测试人员,对吧?)。

如果(修正)B取决于A,那将是微不足道的。你可以ci A然后ci B。

我的问题是当他们独立时(或至少现在看来)该怎么做。

我可以想到以下几种方式:

  1. 为B使用单独的克隆。
  2. 在同一存储库中使用匿名或命名的分支或书签。
  3. 使用MQ(在A之上使用B补丁)。
  4. 使用分支MQ(我稍后会解释)。
  5. 使用多个MQ(自1.6起)
  6. 1和2由excellent blog由@ slightly related question链接的@Steve Losh覆盖。

    与其他选择相比,1的一个巨大优势是,当您从处理一件事物到另一件物品时,它不需要任何重建,因为这些文件在物理上是分开且独立的。所以它真的是唯一的选择,例如,A和/或B触及定义三态布尔的头文件,并被数千个C文件包含(不要告诉我你没有看到这样的遗留代码碱)。

    3可能是最简单的(在设置和开销方面),如果B是一个小的和/或紧急修复,你可以翻转A和B的顺序。但是,如果A和B接触相同的文件,它会变得棘手。如果A和B的变化在同一个文件中是正交的,那么很容易修复无法应用的补丁,但从概念上讲它仍然有点风险。

    4可以让你头晕,但它是最强大,最灵活和可扩展的方式。我默认hg qinit-c因为我想标记正在进行的补丁并推/拉它们,但它确实需要一个概念上的飞跃才能意识到你也可以在MQ repo中进行分支。以下是步骤(mq = hg --mq):

    1. hg qnew bugA;为A做出改变; hg qref
    2. mq branch branchA; hg qci
    3. hg qpop; mq up -rtip^
    4. hg qnew bugB;为B做出改变; hg qref
    5. mq branch branchB; hg qci
    6. 再次使用A:hg qpop; mq up branchA; hg qpush
    7. 采取这么多步骤似乎很疯狂,每当你需要换工作时,你必须hg qci; hg qpop; mq up <branch>; hg qpush。但请考虑一下:您在同一个存储库中有多个命名的发布分支,并且您需要同时处理多个项目和错误修复(对于这类工作,您最好获得保证奖励)。用其他方法很快就会迷路。

      现在我的爱好者们,还有其他/更好的选择吗?


      (更新)qqueue几乎使#4过时了。请参阅Steve Losh的优雅描述here

3 个答案:

答案 0 :(得分:7)

我总是使用命名分支,因为这可以让Mercurial完成它的工作:保存项目历史记录,并记住你为什么要按照源代码的顺序进行哪些更改。考虑到我的工作风格,至少是否有一个或两个克隆坐在磁盘上通常很容易:

  1. 您的项目是否缺少构建过程,以便您可以从源代码中测试和运行事物?然后我会想要只有一个克隆,当我需要在另一个分支上工作时来回hg up

  2. 但是如果你有buildout,virtualenv或其他构建的结构,并且可能在两个分支之间出现分歧,那么执行hg up然后等待构建过程重新运行可以这是一个很大的痛苦,特别是如果涉及设置示例数据库之类的事情。在那种情况下,我肯定会使用两个克隆,一个坐在行李箱的顶端,一个坐在紧急功能分支的顶端。

答案 1 :(得分:3)

似乎没有比我在问题中列出的更多或更好的选择。所以他们又来了。

  1. 每个项目使用一个克隆。
    • 优点:完全分离,因此在切换项目时无需重建。
    • 缺点:工具链需要在两个克隆之间切换。
  2. 在同一存储库中使用匿名或命名分支或书签。
    • 优点:标准hg(或任何DVCS)练习;干净清晰。
    • 缺点:必须在切换和重建之前提交。
  3. 每个项目使用MQ和一个补丁(或多个连续补丁)。
    • 优点:简单易行。
    • 缺点:在切换和重建之前必须qrefresh;如果项目不正交,那就很棘手且风险很大。
  4. 每个项目使用一个MQ分支(或1.6+中的qqueue)。
    • 优点:超灵活且可扩展(针对并发项目的数量)
    • 缺点:在切换和重建之前必须qrefreshqcommit;感觉很复杂。
  5. 像往常一样,没有银弹,所以挑选一个正确的工作。


    (更新)对于任何爱上MQ的人来说,在常规分支(#2 +#3)之上使用MQ可能是最常见和最好的做法。

    如果你有两个并发项目在两个分支上有基线(例如下一个版本和当前版本),那么在它们之间跳转是很容易的:

    hg qnew; {coding}; hg qrefresh; {repeat}
    hg qfinish -a
    hg update -r <branch/bookmark/rev>
    hg qimport -r <rev>; {repeat}
    

    对于最后一步,qimport应添加-a选项,以便一次导入一系列变更集。我希望Meister Geisler注意到这一点:)

答案 2 :(得分:1)

所以问题是,当你被告知停止使用功能A并开始独立功能B时,还有哪些替代选项适用于:如何使用mercurial管理并发开发?

让我们看看删除并发的问题,就像编写线程代码一样 - 定义一个简单的工作流来解决给你的任何问题,并将其应用于每个问题。一旦完成,Mercurial将加入这项工作。因此,程序员A将使用功能A.程序员B将使用功能B.两者都恰好是你。 (如果我们只有多核心的话:)

  

我总是使用命名分支,因为这可以让Mercurial完成它的工作:保存项目历史记录,并记住你为什么要按照源代码的顺序进行哪些更改。

我同意布兰登的观点,但我不知道他是否忽略了A尚未经过测试的功能?在最坏的情况下,代码编译并传递单元测试,但是有些方法实现了以前的要求,有些方法实现了新的。针对之前的签入的差异是我将使用的工具帮助我重新回到功能A的轨道。

您的功能A的代码是否正常进行检查?从功能A切换到处理功能B并不是将代码提交到头部或分支的原因。只签入编译并通过测试的代码。 我的理由是,如果程序员C需要开始使用功能C,那么这个分支的新结账将不再是最好的起点。保持分支机构健康,意味着您可以快速响应,更可靠错误修复。

目标是让您的(经过测试和验证的)代码运行,因此您希望所有代码最终合并到开发和传统分支的头部。我的观点似乎是,我看到分支使用效率低下:代码变得陈旧,然后没有使用,合并变得比原始问题更难。

只有你的选择1对我有意义。一般来说:

  1. 在别人看到你的代码之前,你应该认为你的代码是有效的。
  2. 将头放在树枝上。
  3. 如果其他人正在解决问题,请分支并办理登机手续。
  4. 如果您的自动系统或测试人员仅需要您的代码,请进行分支。
  5. 分支,如果您是团队成员,处理问题。考虑一下头部,见1-4。
  6. 除配置文件外,构建过程应该是一个checkout和一个构建命令。在克隆之间切换比在新程序员加入项目时要困难得多。 (我承认我的项目需要一些工作。)