使用 SVN 中的设置 1),分支是一场噩梦,因为根据策略,当我分支 root 时,我总是必须分支 public_code、shared_lib1 和 shared_lib2。为此,我必须调用svn branch 四次并手动修改svn:externals 属性三次。我可以轻松地在 Mercurial 中分支主存储库并自动为所有子存储库获取新分支吗?
不,子存储库不是那样工作的。顶级存储库中的命名分支不会自动传播到子存储库。如果您在代码中创建了1.x 分支,那么不清楚shared_lib1 是否也应该有1.x 分支。事实上,它可能不应该同时分支顶级代码分支,尤其是当该库被多个不同的顶级项目使用时。
当我进行设置 2) 时,repos 之间的文件系统会有所不同。例如。我将在 repo root 中有 public_code/Makefile,但在 repo public_code 中文件将只是 Makefile。 Mercurial 是否仍然能够在存储库之间同步更改?工作流程会是什么样子?
不,如果您这样创建存储库,则无法在存储库之间进行推送和拉取。当它们来自同一个“母亲”存储库时,您只能在存储库之间推/拉。听起来您将创建三个不相关的存储库。
在这种情况下,您应该仔细评估为什么在 Subversion 中有 svn:externals 以及它们如何映射到 Mercurial subrepositories。它们不是svn:externals 的一对一替代品。您还应该研究对子存储库的工具支持——包括 Mercurial 本身和您的 Mercurial 托管、您的持续构建系统等。我编写了部分 Mercurial 子存储库代码,并且从 Mercurial 2.0 开始,这里和那里仍然存在一些尖锐的边缘。
简而言之,子存储库给您的是子系统之间的非常紧密的耦合。这通常是要避免的 :-) 我们努力使我们的软件系统松散耦合,因为这给了我们灵活性。
子存储库的主要用例是“构建存储库”,您可以在其中跟踪在给定构建中使用的组件的精确版本。您不能要求 Mercurial 跟踪子存储库中给定分支的提示,它始终会跟踪给定存储库中的给定变更集。这使得以后重新创建给定的检出成为可能:.hgsubstate 文件跟踪在每个子存储库中检出的精确变更集。
因此,如果您的 root 存储库不用于开发,而仅用于构建版本,那么子存储库实际上可以为您提供出色的工作。工作流程类似于
$ 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 中工作并且如果他们在root 中对子组件进行更改作为其工作的一部分,则子存储库的工作效果会较差。这表明组件之间的耦合过于紧密:如果主代码依赖于子组件的确切变更集,那么子组件应该直接在主代码中。此外,顶级存储库中的hg commit 将递归并在子存储库中使用与ui.commitsubrepos=True 相同的提交消息。 (在 Mercurial 2.0 中,默认值更改为 False。)这通常是不希望的,当它确实有意义时,那么子存储库的耦合非常紧密,应该是顶级存储库的一部分。
所以,总结一下:如果root 是“构建存储库”,则使用子存储库。否则,您应该内联顶级存储库中的组件,或者您应该使用类似Maven 或类似的东西来更松散地将这些组件耦合在一起以管理依赖项。这些工具通常会让你说“请使用最新版本的 root 及其所有依赖项”,然后你可以在对测试满意时发布正式版本。这些“快照”构建无法精确复制,但这也不是必需的——只有最终版本需要严格和精确的依赖跟踪。