将遗留代码库从cvs转移到分布式存储库(例如git或mercurial)。需要对初始存储库设计提出建议。

12

介绍和背景

我们正在更改源代码控制系统,目前正在评估 Git 和 Mercurial。总代码量约为 600 万行,既不是特别庞大也不是特别小。

首先,让我简要介绍一下当前存储库设计的外观。

我们有一个基本文件夹,包含完整的代码库,在该级别以下有各种用于多个不同上下文的模块。例如,“dllproject1”和“dllproject2”可以看作是完全不同的项目。

我们正在开发的软件是我们称之为配置器,可以根据客户需求进行无限定制。总共可能有 50 种不同版本。但是,它们有一个共同点。它们都共享一些强制性的模块(mandatory_module1 ..)。这些文件夹基本上包含内核/核心代码和常见语言资源等。所有自定义可以是其他模块之间的任何组合(module1 ..)。

由于我们目前正在使用 CVS,因此我们已在 CVSROOT/modules 文件中添加了别名。它们可能看起来像:

core –a mandatory_module1 mandatory_module2 mandatory_module3
project_x –a module1 module3 module5 core

因此,如果有人决定参与项目_x 的工作,他/她可以通过以下方式快速检出所需的模块:

base>cvs co project_x

问题

从直觉上来看,将基础文件夹作为单个存储库似乎不太对。作为程序员,您应该能够检出当前正在使用的项目所需的确切代码子集。您对此有何想法?

另一方面,将每个模块放在单独的存储库中更合适。但这使得程序员更难以检出他们所需的模块。您应该能够通过单个命令来做到这一点。因此,我的问题是:在git/mercurial中是否有类似定义别名的方法?

欢迎提出任何其他问题、建议或指针!

附言:我已经搜索了类似的问题,但感觉没有一个完全适用于我的情况。


刚刚按照要求完成了我的答案,其中包括一些有关分布式版本控制系统的模块管理方面的考虑。 - VonC
1
6百万行代码 ⇒ 不算庞大。啥? - Profpatsch
2个回答

13

这只是一个快速的评论,提醒您:

  • 这些迁移通常提供了重新组织源代码的机会,不是按模块(每个模块有一个存储库),而是按功能域拆分(将同一给定功能域的多个模块放在同一个存储库中)。

然后要使用submodules来定义configuration

  • Git还可以,但从Linus自己承认的角度来看,将所有内容放入一个存储库可能会有问题。
[...] CVS,也就是说它实际上基本上是面向“逐个文件”的模型。
这很好,因为你可以有一百万个文件,然后只检出其中的几个 - 你甚至不会看到其他999,995个文件的影响。
Git从根本上来说从未真正看到少于整个仓库的东西。即使您将事物限制在某种程度上(即仅检出部分内容或将历史记录后退一点),Git最终仍然始终关心整件事情并围绕其周围运转。
因此,如果强制Git将所有内容视为一个巨大的存储库,则其扩展性非常糟糕。我认为那部分确实无法解决,尽管我们可能可以改善它。
是的,那么还有“大文件”问题。我真的不知道如何处理大文件。我知道我们对它们很糟糕。
这两个点主张采用更加组件化的方法来处理大型系统(和大型遗留代码库)。
通过Git子模块,您可以在项目中检出它们(即使这是一个两步骤的过程)。但是您有一些工具可以使子模块管理更加容易(例如git.rake)。
当我在考虑修复一个在多个项目之间共享的模块中的错误时,我只需修复错误并提交,然后所有人都进行更新。这就是我在供应商分支帖子中描述的“系统方法”:每个人都在最新的(HEAD)上工作,对于少数项目来说非常有效。但是对于大量模块来说,“模块”的概念仍然非常有用,但其管理与DVCS不同。
  • 对于密切相关的模块(即“在同一功能领域内”,例如金融领域中与“PNL-利润和损失”或“风险分析”相关的所有模块),您需要使用所有相关组件的最新版本(HEAD)。
    这可以通过使用子树策略来实现,不是为了您发布(推送)对其他子模块的更正,而是为了跟踪其他团队所做的工作。
    Git允许使用额外奖励,即此“跟踪”不必在您的存储库和一个“中央”存储库之间进行,而可以在您和其他团队的本地存储库之间进行,从而允许类似性质的项目之间进行非常快速的来回集成和测试。

  • 但是,对于不直接属于您的功能领域的模块,子模块是更好的选择,因为它们引用模块的固定版本(提交):
    当低级框架发生更改时,您不希望它立即传播,因为它会影响所有其他团队,然后他们必须放下手头的工作来适应该新版本(但是您确实希望所有其他团队知道这个新版本,以便他们不会忘记更新该低级组件或“模块”)。
    这使您仅使用其他模块的官方稳定标识版本,而不是潜在的不稳定或未经充分测试的HEAD。


谢谢您的回复。我猜对于我(或许是大部分使用单一非分布式存储库的用户)来说,最大的障碍就在于思维定势。我的意思是,您如何看待事物以及如何组织您的代码等方面。我开始逐渐领会其中奥妙。待续。 - ralphtheninja
1
所以你更或多或少地在说,你必须放弃(也许不完全)“模块思维”。当我考虑修复在几个项目之间共享的模块中的错误时,我只是修复错误并提交,所有人都会更新。但是使用git,projectA中的“相同”模块是它自己的存储库,而projectB中的另一个存储库呢?因此,当我在该模块的存储库版本中修复错误时,他们可以从我那里拉取更改。 - ralphtheninja

5
就Mercurial方面而言,建议将大型遗留的CVS/SVN代码库重构为较小的组件。通用代码应该放到自己的库中,然后应用程序代码将依赖于这些库,类似于它如何依赖于其他库。
Mercurial有forest extension,它允许您管理“源树”“森林”。采用这种方法,您可以将几个较小的存储库合并成一个较大的存储库。对于CVS,您则相反:您要检出大型存储库的较小部分。
我个人还没有使用过forest扩展,但是它的页面说应该使用与Mercurial捆绑的更新版本。但是,像Sun在其OpenJDK项目中一样,它确实被大型组织使用。
还有目前正在进行的工作,将子存储库报告直接添加到Mercurial核心中,如Mercurial wiki中的nested repositories page所设计的那样。

+1 用于回答。我会研究一下的。谢谢 :) - ralphtheninja
1
截至版本1.3(2009年7月1日),Mercurial已经内置了子模块支持的开端,名为“subrepos”(http://mercurial.selenic.com/wiki/subrepos)。我不会假设该功能会立即稳定下来,但它正在到来。 - quark

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