在SVN中构建大型多应用程序代码库的正确方法是什么

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

标签: svn version-control organization

我们目前只有一个代码为http://John.svn.cvsdude.com的repo,只有一个SVN项目http://John.svn.cvsdude.com/MyProject,其中包含一些用于单个Visual C ++解决方案的子目录

这一切都是作为一个应用程序开始的,虽然我们确实拆分了单独的库项目以供将来重用,但它仍然是完全相同的SVN项目。让我们说我们的目标是让多个应用程序在使用的库中有一些重叠,在SVN中设置它的正确/最佳方法是什么?当然,人们可以保留一个SVN项目,并将应用程序项目和图书馆项目作为子目录,但它似乎不太合适。

假设我们有App1,App2,App3和LibraryA,LibraryB,LibraryC,LibraryD,这些都是独立的项目/解决方案......您如何在一个(或更多的回购)下组织这个?有最好的做法吗?

3 个答案:

答案 0 :(得分:2)

将所有内容保存在一个存储库中,并将每个项目和库放在存储库的单独根目录中(请参阅Planning Your Repository Organization详情)。

请记住,存储库结构不必与磁盘上的项目文件结构相同。

此外,我使用svn-externals 在各种项目中共享库目录(作为存储库的单独根文件夹保存)。

答案 1 :(得分:2)

这是来自Codelab Cloud Services的CollabNet的Jack。首先,感谢您成为一名代理客户!

你用“项目”来描述你的情况,但这是一个含糊不清的术语,而Subversion本身根本没有任何概念。这里真正的考虑因素不是Subversion本身,而是您的构建工具和发布策略。您希望配置最能支持您想要做的事情。

例如,所有这些应用程序和库是否一次性发布?完全独立?有些混合?这个答案可能会改变吗?

如果它们都立即发布,那么尽可能简单地确定每个应用程序的哪些版本与其他应用程序的版本一起发布是非常重要的。这样,可以以一致,一致的方式验证错误报告,实施修复程序和修补程序。要做到这一点,我会使用几个人建议的“/ app / {trunk,tags,branches}”结构,而是坚持规范

/trunk/app1
/trunk/app2
/tags/TAGNAME/app1
/tags/TAGNAME/app2
/branches/BRANCHNAME/app1
/branches/BRANCHNAME/app2

结构。这允许您在一个命令中分支,标记和合并整个树,所有应用程序和库:

svn cp URL/trunk URL/tags/TAGNAME

另一方面,如果这些事情是独立的,那么你最好用

/app1/trunk
/app1/tags
/app1/branches
/app2/trunk
/app2/tags
/app2/branches
...

这样,例如,标记一个应用程序不会影响另一个应用程序。

在一个混合的情况下,您仍然可以实现协调的分支(在适当的时候),但是您必须在工作副本中使用分支,并且可能使用稀疏检出(如果工作副本很大)。或者,您可以标记或分支整个存储库,即使标记或分支对大多数存储库没有意义:Subversion标记和分支存储起来很便宜,并且(如果使用“svn cp”的URL到URL形式) “)便宜;不用无关标签标记事物的唯一原因是,它使人类感到困惑。但这是一个非常强大的原因,所以混合模型最好用“app / trunk”结构处理,以避免混淆。

您可以在Apache Foundation存储库中找到“/ app / trunk”方法的好例子。所有Apache项目(包括Subversion本身)都存储在一个Subversion存储库中。那里有大约100个项目,尽管存在一些相互依赖关系,但它们都是独立管理的。从root of all ASF projects开始,您可以浏览这个巨大的回购(可能是公共世界中最大的单个Subversion回购)。实践中有一些多样性,但有一个很好的例子是Subversion itself

另外值得注意的是:就Subversion而言,你可以随时改变这些东西。 “标签”和“分支”实际上只是副本;你可以随心所欲地重新安排你喜欢的东西。但有一些警告:

  • 它会让人混淆
  • “树冲突”(添加,删除,移动或重命名文件或目录)可能会使以后的合并变得痛苦。合并工具的功能是为您节省工作。所有合并工具最终,为了一个足够的合并,将决定权交给人类;重要的问题是如果没有它,他们能够做多少。树冲突导致当前的Subversion(1.6或更高版本)比你想要的更频繁。因此,最好不要经常重新排列这些顶级目录,并准备好进行干预和清理任何跨越此类重新排列的合并。

答案 2 :(得分:0)

我建议将以下布局放在同一个存储库中:

App1\
    trunk
    tags
    branches
App2\
    trunk
    tags
    branches
App3\
    trunk
    tags
    branches
LibraryA\
    trunk
    tags
    branches
LibraryB\
    trunk
    tags
    branches
LibraryC\
    trunk
    tags
    branches
LibraryD\
    trunk
    tags
    branches

现在,我对你的发布时间表做了一些假设。我假设每个应用程序和库都按照不同的时间表发布。实际上这是最糟糕的情况,但我的计划将允许这样做。每个应用程序都需要预先编译其依赖项并将其包含在存储库的目录中。这是App1的外观,因为它依赖于库B和C:

App1\
    trunk\
        deps\
            LibraryB, release 1.1
            LibraryC, release 4.3
    tags
    branches

这意味着无论何时分支主干,您都将获得必要的库,这极大地简化了操作。注意它是库的编译二进制文件,而不是它们的源。

trunk的分支将使用上述版本,并且由于您不允许修改它们,因此任何错误修正都需要进入App1。同时,要使用新版本的LibB& C,您可以在图书馆团队发布版本时更新他们的版本。因此,一段时间后,您的存储库可能如下所示:

App1\
     trunk\
         deps\
             LibraryB, release 1.3
             LibraryC, release 4.4
     tags\
         release-1.0\
             deps\
                 LibraryB, release 1.1
                 LibraryC, release 4.3
     branches\
         stable-2.0\
             deps\
                 LibraryB, release 1.2
                 LibraryC, release 4.2

允许在trunk中使用最新的库版本。 release-1.0使用固定版本(这里是最旧的版本),而stable分支使用的是以前版本的库。

上述计划是我在上一个雇主那里想到的,但从未实现过。要使其工作,您需要将代码库拆分为应用程序/库,并且可以并行进行开发。对我们来说情况并非如此。但我坚信,这是一个值得追求的目标。

祝你好运!

P.S。我强烈建议反对 svn:externals。他们可以使分支机构管理变得更加困难。例如,如果外部更改和分支依赖于它,则存在弄乱该分支的风险(例如,使其无法编译)。