带有大型公司通讯,配置管理和测试要求的Mercurial存储库结构


16

我还是另一个Subversion用户,他在分布式版本控制的Tao中苦苦地对其自身进行重新教育。

使用Subversion时,我非常喜欢次项目方法,并且与大多数以前的雇主一样,我们将构建存储库分支;标签和主干如下:

branches-+
         +-personal-+
         |          +-alice-+
         |          |       +-shinyNewFeature
         |          |       +-AUTOMATED-+
         |          |                   +-shinyNewFeature
         |          +-bob-+
         |                +-AUTOMATED-+
         |                            +-bespokeCustomerProject
         +-project-+
                   +-shinyNewFeature
                   +-fixStinkyBug
tags-+
     +-m20110401_releaseCandidate_0_1
     +-m20110505_release_0_1
     +-m20110602_milestone
trunk

在实际的源代码树本身中,我们将使用(类似)以下结构:

  (src)-+
        +-developmentAutomation-+
        |                       +-testAutomation
        |                       +-deploymentAutomation
        |                       +-docGeneration
        |                       +-staticAnalysis
        |                       +-systemTest
        |                       +-performanceMeasurement
        |                       +-configurationManagement
        |                       +-utilities
        +-libraries-+
        |           +-log-+
        |           |     +-build
        |           |     +-doc
        |           |     +-test
        |           +-statistics-+
        |           |            +-build
        |           |            +-doc
        |           |            +-test
        |           +-charting-+
        |           |          +-build
        |           |          +-doc
        |           |          +-test
        |           +-distributedComputing-+
        |           |                      +-build
        |           |                      +-doc
        |           |                      +-test
        |           +-widgets-+
        |                     +-build
        |                     +-doc
        |                     +-test
        +-productLines-+
        |              +-flagshipProduct-+
        |              |                 +-coolFeature
        |              |                 +-anotherCoolFeature
        |              |                 +-build
        |              |                 +-doc
        |              |                 +-test
        |              +-coolNewProduct
        +-project-+
                  +-bigImportantCustomer-+
                  |                      +-bespokeProjectOne
                  |                      +-bespokeProjectTwo
                  +-anotherImportantCustomer-+
                                             +-anotherBespokeProject

这个想法曾经是(现在仍然是)使用存储库的结构来帮助工程团队之间进行结构化的沟通。业务中面向客户的部分以及其他利益相关者和领域专家。

举例来说:位于“项目”目录之一中的源文档只能使用一次(并赚钱)。位于“ productLines”目录之一中的文档的收入与该特定行中的产品被出售的次数相同。位于“图书馆”目录之一中的文档的收入是使用它们的任何产品售出的收入的多少倍。

它使费用摊销的概念变得明确,并有助于建立对整个企业中源文档重用的支持。

这也意味着我们的构建自动化工具可以在一个通用结构上运行。(我们的构建脚本在源代码树中查找“ build”文件夹,在其中找到配置文件,这些文件指定了如何构建每个组件;用于文档生成和测试的过程类似。)

值得注意的是,我使用的产品通常需要很长时间才能进行性能测量和特性测试。20至200小时;生成介于几GB到几TB之间的已处理测试结果/中间数据(必须存储并绑定到特定的系统配置,以便可以衡量性能随时间的提高)。这个问题使配置管理成为一个重要的考虑因素,并且还对集中化提出了一些要求,因为通常运行性能测量和特性测试所需的计算资源是有限的。(64-128个内核的小型集群)。

最后一点:持续集成系统知道需要触发构建;静态分析;烟雾测试和单元测试在每次修改主干,每次修改任何“标签”分支以及每次修改任何“ AUTOMATED”分支时进行。这样,单个开发人员便可以将CI系统及其个人分支(IMHO的一项重要功能)一起使用。

现在,这是我的问题:如何使用Mercurial复制以上所有内容(如果可能,请进行改进)。

- 编辑:

我当前的思路是使用中央Subversion存储库定义整体结构,但允许将hg用作客户端,以便开发人员可以在本地使用存储库。


1
哇。我认为,对此的一个很好的答案将是一篇很长的论文。
Ed James

我认为关键问题是代码合并的方式和位置,因为这可能会定义阻力最小的路径。那么,代码如何合并?
Wyatt Barnett 2012年

通常,合并可能来自个人分支到项目或功能分支,然后到主干。我从来没有遇到过太多的合并困难(我们在Win32上使用过TortoiseSVN),尽管我们从未运行太长时间(最多一次迭代)而又没有集成到主干中。尽管我们的目标是简化人员管理而不是开发工作流程,但我们还是倾向于在主干中完成大部分工作。(一个开发负责人,许多独立工作的开发人员,因此将所有事情都保留在主干中使开发负责人更容易跟踪发生的事情。)
William Payne 2012年

一个关键点是严重依赖CI系统驱动的测试,尤其是在系统测试级别。这是为了建立信心,使不同开发人员不会互相干扰,并促进许多小迭代的想法。(此外,运行系统测试所需的计算繁重工作意味着,如果人们主要在干线上工作,那么对计算资源的争用就会减少)。
威廉·佩恩

Answers:


10

Spoike的回答很好,但是我认为有一些值得补充的地方太大了,无法发表评论。

分支机构

使用Mercurial,您可以愉快地忽略整个第一个组织结构图。正如Spoke所说,每个存储库都有自己的一组标记,分支(命名的和匿名的),并且可以根据业务需要进行组织。

如果bespokeProjectTwo需要特殊版本的charting库,则可以分支charting,添加新功能并在中使用它bespokeProjectTwo。引用标准charting库的其他项目将不会使用新的功能(及其错误)。如果主charting库中的错误已修复,则可以将这些更改合并到分支中。如果其他项目也需要这些工具,则可以使这些项目使用特殊分支,或者将分支合并到主线中并关闭分支。

同样,没有任何阻止您制定结构分支名称以提供诸如AUTOMATION分支之类的特定功能的策略。

目录组织

没有理由不能完全保持源目录与Mercurial一样。唯一的区别是,使用Subversion时,您只有一个整体(src)存储库,而使用Mercurial时,最好拆分成逻辑分组的存储库。从您的源树结构中,我可能会提取以下每个内容作为单独的存储库:

src-+
      +-(developmentAutomation)
      +-libraries-+
      |           +-(log)
      |           +-(statistics)
      |           +-(charting)
      |           +-(distributedComputing)
      |           +-(widgets)
      +-productLines-+
      |              +-(flagshipProduct)
      |              +-(coolNewProduct)
      +-project-+
                +-bigImportantCustomer-+
                |                      +-(bespokeProjectOne)
                |                      +-(bespokeProjectTwo)
                +-anotherImportantCustomer-+
                                           +-(anotherBespokeProject)

这允许任何产品定制项目使用任何版本的库的任何组合。查看Mercurial子存储库,以一种简单的方式来管理将哪个库用于产品或项目的任何给定版本。

工作流程

Spoike建议的工作流程(开发人员从受祝福的仓库中提取,在本地工作,发出提取请求,最后由集成商提取这些更改并将其合并)的替代方法是将连续集成系统用作中介。

和以前一样,开发人员从受祝福的存储库中提取并在本地工作,但完成后,他们会再次从受祝福的存储库中获取并合并自身,然后再推送到不受祝福的存储库中。然后,未经许可的仓库中的任何更改都将被审核(手动或自动),并且只有在批准后才能移动到祝福的仓库中。

这意味着集成商只能接受或拒绝更改,而不能进行合并。以我的经验,编写代码的开发人员执行合并几乎总是比其他人更好。

如在水银书中所建议的,钩子可以用来自动执行此过程:

当有人将变更集推送到每个人都从中拉出的服务器时,服务器将在接受变更集作为永久变更集之前对其进行测试,如果该变更集未通过测试套件,则拒绝该变更集。如果人们仅从此筛选服务器中提取更改,它将确保已自动审核人们提取的所有更改。

其他问题

大型测试数据集的问题也可以通过将测试数据放入水银子存储库中来解决。这将防止代码存储库充斥测试数据,同时仍将测试数据保持在版本控制之下。


再次,另一个出色而有用的答案。谢谢。
威廉·佩恩

RE:分支机构。我同意可以很容易地忽略第一个组织结构图。无论如何,它不能很好地传达工作流程,因此除了加强约定外没有提供任何实际用途。但是,我想用一种可以强烈传达(尽可能简单)工作流程并鼓励频繁提交的东西来代替它。也许将主要的“ trunk / development”分支称为“ daily”会做到这一点?
威廉·佩恩

RE:目录组织。我使用源目录组织作为沟通的下层手段。在代码的组织上(以及整个业务上)强加一个隐式结构。我开始理解,Mercurial往往以非常非常灵活的方式使用。但是我真的想限制这种灵活性,以便通过在工作站和我们的网络存储区域上组织文档的方式强加一个结构,从而在人们思考业务的方式上强加一个结构。(公司通讯多于技术通讯。)
威廉·佩恩

RE:工作流程。我认为最简单的工作流程是从“每日”存储库中取出,在本地进行处理,然后(经常)推回“每日”存储库,通过CI系统启动静态分析,冒烟测试和回归测试。只要我知道它,并且只要它很快又被修复,我就很高兴主仓库被“破坏”。实际上,我正在考虑将“每日”回购作为唯一的编译和构建方式,以鼓励频繁的提交和良好的测试覆盖率。(恕我直言,这比孤立工作的能力更重要)。
威廉·佩恩

@WilliamPayne-谢谢。尽管Mercurial是灵活的,但有了适当的存储库,分支和挂钩,您可以在组织或存储库级别建立任何所需的限制。就个人而言,我将从组织控制和一些CI挂钩开始,并在将来这些控制变得明显时扩展这些控制。同样,明智地使用子仓库可以例如鼓励人们以与服务器上相同的结构在本地检查事物,例如通过拥有productLinesbigImportantCustomer作为超级仓库。
Mark Booth

9

好吧,尝试简单地回答这个问题。

你需要知道的

您需要了解的第一件事:Mercurial是分布式版本控制,并且具有一些您应该了解的属性,在下面列出。

  • 源来自一个存储库,可以在其中克隆该存储库。所有克隆的存储库都可以通过同步(使用pull和push命令,可以限制访问)彼此共享代码。
  • 每个拥有代码副本的用户都具有存储库的克隆。如果要分支,则可以在其本地克隆中进行。这意味着您不需要组织每个用户应该如何分支。他们可以自己做。
  • 标签是通过提交创建的(与git中的硬标签相同)。这意味着您不需要在存储库结构内的目录中放置标签。
  • 人们在DVCS中使用的常用模型(在github和bitbucket中使用)是半集中式的。

    每个用户都有一个公共存储库(在某些共享中或在安全服务器上)和一个私有存储库(在他们自己的工作站中)。它们都是集成商“ blessed”存储库的克隆。每当他们觉得准备好发布代码时,就可以将更改推送到其公共存储库。然后,集成者可以选择哪些用户将代码拉入“祝福”存储库。

    如果集成商不能轻松地合并某些用户的代码,则更改将被拒绝,具体取决于该特定用户来更新其存储库并自行修复合并。如果您经常合并(因为需要合并的代码较少)通常并不那么困难,并且通常用户应该知道合并出了什么问题。

每个项目的存储库设置

因此,通常的设置是每个项目都有以下内容:

  • 集成商负责的公共只读存储库。这是“祝福”。

    也就是说,所有用户都可以提取/获取内容,但无权对其进行推送。

  • 每个用户都可以拥有自己的存储库公共克隆。

    设置为共享驱动器中最简单的设置(尽管您可能考虑托管诸如bitbucket)。集成商从用户那里接收拉取请求,并尝试从这些存储库中拉取新代码。合并顺利完成后,会将其放入只读存储库中。如果不是,则要求用户修复通过在本地为自己更新和合并而引起的合并冲突。

  • 每个用户都可以拥有自己的存储库专用克隆。

    优良作法是从公开的克隆中撤出,但无论是从公开的还是从集成商中撤出都没关系。所有提交都是唯一可识别的,因此合并提交而您忘记在公共场合获取的提交则相对容易修复(通过将更改从私有更改推送到公共,它也会自动获取集成商的更改)。

源代码组织

就像如何安排项目源本身一样,您需要仔细考虑。如果需要对工件进行源代码控制,则将其置于源代码控制中。我个人不喜欢检入由构建或运行时产生的工件的想法(由于在这类工件上合并冲突的高风险),例如二进制文件或日志文件。

您还可以签入配置,只要它们使开发人员可以轻松进行并且不影响发行版或实时/生产环境的配置(例如应用程序/ Web服务器设置)。这导致一个想法,即如果您的配置严重阻碍了开发人员在签出代码后的五分钟之内启动,则需要对其进行重构。另一个要求是,对于开发人员来说,破坏发布或实时/生产环境应该是一件令人头疼的事情。

您提到您具有需要绑定到某些版本的代码的测试数据。现在,这有点棘手,因为当您检入巨大数据时,Mercurial和Git等DVCS系统趋向于变慢。以我的经验,在5 GB的二进制文件之后,它变得实在无法忍受(您的使用期限可能会有所不同,因此您应该测试一下它的工作方式)。但是,我建议您将生成的数据放入其自己的存储库中,并让您的测试系统在签入它们时适当地标记它们(和/或出于相同的元数据目的创建文本文件)。

我希望这一切都有意义。如果我错过了一些细节或需要进一步解释,请在下面发表评论,我将尝试进行编辑。


+1是一个非常不错的回答,有几个非常有用的要点。在回答您的答案的第一部分时,我没有掌握每个拥有自己的公共存储库的用户的重要性。也许我需要更多地考虑如何组织对等工作流。
威廉·佩恩

针对您回答的第二部分,在我看来,为整个组织建立一个单一存储库的全部目的是为工作的结构创建一个共享的心理形象,并使其更容易找到可以被重用。(非常像大教堂而不是集市,但这就是我工作的环境)。我真的很想知道如何使用DCVS达到相同的结构化组织(归档系统)的感觉。
William Payne 2012年

针对您的回答的第三部分:我完全同意源代码控制系统用于源文件,派生的人工制品不属于该文件。我也同意在VCS中存储任何描述的大型二进制文件是不切实际的。但是,我确实相信您可以将大型二进制文件存储在约定的网络位置(具有定义的名称),并从VCS内引用它们。例如,构建环境可以存储为命名的VM磁盘映像,并可以从各种构建脚本中引用。(例如:在build_env_A上构建我)。测试数据也是如此。
威廉·佩恩

过去,我使用了网络驱动器上的目录层次结构,其中目录名称来自于Subversion修订版本号+分支位置的哈希值,以将中间文件和测试结果绑定到特定的修订版本。这意味着我们具有可追溯性,而无需在版本控制中存储派生文件。
威廉·佩恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.