适应迁移到Mercurial的svn:externals用法

4
我们在企业环境中拥有一个svn仓库结构,看起来像这样:
root
  libs
    shared_lib1
    shared_lib2
    private_lib
  public_code
  private_code

在这里,public_code是一个外部仓库,是开源的,公司外的人可以读写。shared_lib1和shared_lib2也是外部库,被另一家公司的一组程序员共享。我是维护者,并且可以做出技术上最好的选择,外部用户必须作出相应调整。

现在,我想知道从这种结构到一个mercurial仓库的最佳方法是什么。

1)我可以使用mercurial子仓库来紧密模拟旧设置。 或者
2)我可以为我们创建一个大型repo,并为外部合作伙伴创建三个新的较小、独立的仓库(因此基本上是forking projects),并在大型仓库和独立仓库之间交换changeset。

如果在svn中采用设置1),分支是一场噩梦,因为我总是需要在分支root时分支public_code、shared_lib1和shared_lib2。为此,我必须调用svn branch四次,并手动修改三次svn:externals属性。在mercurial中,我是否可以轻松地分支主仓库并自动获取所有子存储库的新分支?

当我进行设置2)时,文件系统将不同于仓库之间。例如,在“根”仓库中,我将有public_code/Makefile,但在“public_code”仓库中,文件将仅为“Makefile”。Mercurial仍然能够同步仓库之间的更改吗?工作流程可能是什么样的?

1个回答

5
在SVN的设置1)中,分支是一场噩梦,因为我根据政策总是必须在分支root时分别分支public_code、shared_lib1和shared_lib2。为此,我必须调用svn branch四次,并手动修改三次svn:externals属性。我能轻松地在Mercurial中分支主repo并自动获取所有子repo的新分支吗?
不,子repo不是这样工作的。顶层repo中的命名分支不会自动传播到子repo。如果您在代码中创建了1.x分支,则不清楚shared_lib1是否也应该有1.x分支。实际上,它可能不应该在顶层代码分支同时进行分支,特别是如果该库被多个顶层项目使用。
当我进行设置2时,存储系统将在不同的仓库之间发生变化。例如,在仓库“root”中,我将有public_code/Makefile,但在仓库“public_code”中,该文件将仅为Makefile。Mercurial还能够在这些仓库之间同步更改吗?工作流程可能是什么样的?
不行,如果您像这样创建它们,就无法在仓库之间进行推送和拉取。只有在它们源自相同的“母”仓库时,才能在仓库之间进行推送/拉取。在这里,听起来您将创建三个不相关的仓库。
在这种情况下,您应该仔细评估为什么在Subversion中有svn:externals以及它们如何映射到Mercurial subrepositories。它们不是svn:externals的一对一替代品。您还应该研究子存储库的工具支持 - 包括Mercurial本身、您的Mercurial托管、持续构建系统等等。我编写了部分Mercurial子存储库代码,截至Mercurial 2.0,仍然存在一些棘手的问题。
简而言之,子存储库给您提供的是子系统之间非常紧密的耦合。通常情况下应该避免这种情况 :-) 我们努力使我们的软件系统松散耦合,因为这样可以给我们带来灵活性。
子仓库的主要用途是建立一个“构建仓库”,在其中跟踪您在特定构建中使用的组件的精确版本。您不能要求Mercurial在子仓库中跟踪给定分支的tip,它将始终跟踪给定仓库中的给定变更集。这就使得以后可以重新创建给定的检出:.hgsubstate文件跟踪了每个子仓库中已经检出的精确变更集。

因此,如果您的根仓库不用于开发,而只用于构建发布,则子仓库实际上可以非常适合您。工作流程将类似于:

$ cd root
$ cd libs/shared_lib1
$ hg pull
$ hg update 2.0
$ cd ../..
$ make test && hg commit -m "Updated to sharedlib1 2.0"
$ hg tag 2.3

你随后发布了软件的2.3版本,Mercurial知道它依赖于“shared_lib1”的2.0版本。当子组件负责人告诉你有新版本可用时,你会不时地这样做。当然,你的CI服务器可以每晚执行此操作以查看组件是否能够协同工作!
如果开发人员直接在“root”中工作并作为其工作的一部分更改子组件,则子存储库的工作效果较差。这表明组件之间耦合过紧:如果主代码依赖于子组件的确切变更集,那么子组件应直接包含在主代码中。此外,在顶级存储库中进行“hg commit”将递归并在ui.commitsubrepos=True时在子存储库中使用相同的提交消息。(默认值在Mercurial 2.0中更改为False)。这通常是不希望的,当确实有意义时,子存储库与顶层存储库非常紧密耦合,应成为顶层存储库的一部分。
因此,总结一下:如果root是“构建存储库”,则使用子存储库。否则,您应该将组件内联到顶级存储库中,或者通过使用类似Maven的东西更松散地将这些部分耦合在一起来管理依赖项。这些工具通常会让您说“请使用root的最新版本及其所有依赖项”,然后在测试满意时进行正式发布。这些“快照”版本无法精确重现,但这也不需要-只有最终版本需要严格和精确的依赖关系跟踪。

非常感谢您提供如此有帮助且详细的答案。 - fschmitt
对于使用类似Maven的构建工具管理依赖项的部分,给予加1。 - Laurens Holst

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接