【问题标题】:? Structuring a Revision Control System (SVN) to Handle Dependencies?构建修订控制系统 (SVN) 以处理依赖关系
【发布时间】:2010-11-02 15:02:54
【问题描述】:

多年来,我一直在以一种简单的方式进行编程:我会将源文件保存在按语言和项目组织的目录中,偶尔进行手动备份,如果我很聪明,我会在尝试之前复制一份新版本;差不多就这些了。

我最近决定开始使用修订控制。在检查了一堆文章和页面,并尝试了很多不同的之后,我最终选择了 Subversion(尽管它由于 BASE 使项目规模翻了一番)。


我现在需要一些我似乎无法找到有用信息的方面的建议。首先,我正在检查我是否具备正确使用 RCS 的基本流程:

  1. 将我的所有项目导入到 SVN 存储库中
  2. 删除原件
  3. 从存储库中签出项目
  4. 继续努力
  5. 提交

就这样?那么新项目呢?我必须在文件夹中创建一个新项目然后导入它吗?


我的目录结构也有问题,但首先,我可能应该布置一下我的设置。我是在我的家用机器上工作的单一开发人员。我的数据目录中有以下布局:

X:\数据 \H \第三方 \图形 \控件 \这个控件 \那个控制 \库 \类 \CFoo \CBar \VC \大的 \酷应用 \res \小的 \CoolerApp \res \杂项 \测试 \CFooTest

……等等。

我的 IDE 的包含路径中有几个我经常使用的头目录(例如 3rdParty\GraphicsClasses\CFoo 等)。依赖关系之前已经存在问题,但现在有了 RCS,情况就更糟了。例如,CoolApp 可能包含 ThisControlCFoo。以前,如果我在开发 CoolApp 时修改了 CFoo 并破坏了它,其他使用它的应用程序(例如 CoolerApp)就不太理想了因此也会被破坏。

我这样做而不是复制 CFoo 等的原因。人。 CoolApp 和其他人的目录是因为尝试将每个副本中的更新合并回 \H 文件夹中的主副本很麻烦。 p>

我原以为通过使用正式的 RCS,可以避免此类问题。但是,现在发生的情况是,当我将项目从 \VC\CoolApp 等导入 SVN 存储库时,CFoo、*Libraries\** 等组件等不包含在内,因为它们位于外部目录中,因此没有版本控制——从而破坏了整个观点。

我正在寻找有关如何处理这种情况的提示。例如,如果我在 \H 中有 CWidget,在 \H 中有 WidgetTest(一个包含 CWidget 的测试容器) em>\VC,那么我将如何构造使得 WidgetTestCWidget 都得到版本控制的东西,同时尽可能地简化它以供其他人使用使用 CWidget 来包含和使用最新版本的应用程序?


另外,我只能将所有项目导入到同一个存储库目录中,丢失了 Big\Small\Test\等结构。我无法让 Subversion 保留它。


最后,原始项目目录会变成什么?我至少看过一篇文章说一旦将它们导入存储库就可以删除它们。如果是这样,我可能会将它们压缩并收起来。



哦,我目前在我的 Apache 服务器上设置了 Subversion,并安装了 VisualSVN、SVNServe 和 CollabNet SVN 服务器。我已经让每个人都工作了,但我很想得到一些建议,因为我确信我只需要一个。



非常感谢。

【问题讨论】:

    标签: svn directory dependencies components structure


    【解决方案1】:

    好的,我将专注于您问题的共享项目部分,因为我刚来自一个工作场所,我们有多个项目和多个共享项目在颠覆中。

    我建议最重要的第一件事是你开始工作时有以下想法:“在硬盘上的任何位置检查项目的主干是能够构建所需的全部内容解决方案”

    还请记住,没有更改的工作副本没有价值。您在磁盘上的哪个位置检查并删除工作副本不应该让您感到恐慌,因为您可以再次检查主干并立即启动。我发现在我以前的地方,我非常注意“设计”开发环境并将所有东西放在正确的地方。这是荒谬的,花在这上面的时间一去不复返了。做一次,在一个不错的源代码控制(如 svn、git 或 TFS)中做,很高兴您现在可以像昨天的报纸一样浏览工作副本。

    工作副本唯一具有任何价值的情况是存在尚未提交的任何修改。 任何有价值的工作副本都容易受到攻击。始终在可行的情况下尽快提交修改。任何形式的硬盘驱动器故障(包括工作副本损坏)、意外删除、从可行的东西更改为不可行的东西等都可能会丢失您的大量工作 - 这是有价值的部分。如果您的半成品代码不适合在项目的主干中看到,请创建一个分支并提交。

    这意味着您将能够在驱动器的不同位置检出同一项目的多个版本并进行处理(例如,开发和实时错误修复版本)。这也意味着检查主干将关闭该工作副本文件夹下的所有依赖库。

    这也意味着在 IDE 级别定义标头/库所在的位置是行不通的。这是视觉工作室引入的一个糟糕的想法,但它们也允许您在单个项目设置中使用相对文件夹指定这些东西 - 它应该在哪里。相信我,如果您使用 IDE 级别的位置定义,在某些时候您将构建您的应用程序并尝试找出您的更改没有出现的原因。然后当你意识到你刚刚针对一个旧的、有缺陷的库版本构建了你的最后 3 个版本时,你会感到下沉。至少我做到了。

    要达到这种乌托邦式的情况,如果您将每个项目和库(例如 CoolApp、CFoo、ThisControl、CWidget)视为具有独立发布周期、主干等的独立项目,您会做得更好。转向独立思考这些事情,分别开发和发布它们。

    这听起来像是很多开销,但如果您想在不破坏使用它的其他项目的情况下对共享组件进行更改 - 这是必要的。

    考虑到这一点,我建议您像这样构建您的存储库:

    /Projects
     /CoolApp
      /trunk
      /branches
      /tags
    /Libraries
     /CFoo
      /trunk
      /branches
      /tags
     /CWidget
      /trunk
      /branches
      /tags
     /ThisControl
      /trunk
      /branches
      /tags 
    /Vendor
     /NUnit
      /current
      /1.6
      /1.7
    

    如果您的存储库当前没有这样设置,您可以使用 svncopy 来构建它。您可以在顶层使用标签/主干/分支,并在下面使用所有内容,但在我看来,这样做会使从概念上分离项目变得更加困难。

    现在只检查主项目 (CoolApp) 的主干。当然 - 这不会按原样构建,因为没有任何依赖项目存在。 下一步是将其他项目添加为externals。使用 tortoisesvn 右键单击​​工作副本的顶层文件夹并转到 svn->properties。添加一个名为“svn:externals”的新属性。以格式定义属性

    /repository_location[@revision]    working_copy_folder
    

    所以对于coolapp,你可以添加以下svn:externals定义:

    /Libraries/CFoo/trunk        CFoo
    /Libraries/CWidget/trunk     CWidget
    /Libraries/ThisControl/trunk ThisControl
    

    完成后,提交更改,然后执行“更新”,您的外部组件也会被关闭。

    您可以使用这种外部定义形式构建您喜欢的任何工作副本文件夹结构。您必须修改解决方案文件以在新位置查找项目,但这通常不是什么大问题。

    一旦你开始以这种方式工作,请注意,让外部指向主干通常是一个非常糟糕的主意。这是因为当库的主干因另一个项目而更改时,当您对解决方案进行新的检查(或更新)时,突然间您的完美解决方案将无法构建 - 即使您认为您没有更改其中的任何内容。 开始为您的库制作标签,并将您的外部对象指向它们。这是当您开始将您的库视为独立的项目时。

    这是另一个原则的情况:“对项目的任何更改都必须在主项目的主干中具有相应的修订” 将外部位置更改为指向新的库版本是能够说“嘿,我现在在这里使用第 2 版的傻瓜”的完美示例。上一段的问题是因为代码在你“下面”发生了变化。

    要修改库,您最好签出该库主干的工作副本,对其进行修改并用新的版本号标记它。然后在主项目中,将external改为指向新标签并更新。

    您可以通过将库位置从标签“切换”到主干来缩短此过程。这样,当您提交时,您会将库更改提交到主干。但是,以这种方式工作,您需要记住外部仍然指向标记 - 您仍然需要标记您的库并更改外部项目,否则将无法构建新的结帐。

    如果您依赖任何第三方工具,例如 nAnt 或 nUnit - 将它们作为供应商分支添加到存储库并通过外部引用它们。 VS 允许您通过浏览来引用 dll,这比 GAC 更灵活。对于单个开发人员来说,这听起来可能不是什么大问题,但是如果您尝试一次升级 nUnit 一个项目,您会发现能够检查项目的主干并知道您'已经获得了正确版本的 nUnit(而不是必须卸载 nUnit 并重新安装正确的版本)。

    还请注意,您的解决方案中的每个项目都没有必要作为单独的外部项目。只有可以或应该在不同项目之间共享的东西才应该分开。

    最后,一旦你启动并运行,我真的建议使用构建引擎,如 CruiseControl.Net 或 Hudson(我最喜欢的)。这可以让您快速反馈任何问题,以免它们被忽视并从背后咬住您。

    好的,我现在就停下来,我不打算去争取“最长答案”徽章。

    【讨论】:

    • 感谢您的建议。我将按照您的建议将我的库和类分开项目。但是,我无法弄清楚如何正确构建我的存储库。目前它类似于以下内容。
       \Repository \App1 \App2 \ThisApp \SomeClass \FooLib \a_third_party_library \... 
      我尝试了几种方法来将它们分类如下,但我无法让它工作。
       \Repository \3rdParty \a_third_party_library \BigProjects \App1 \SmallProjects \App2 \ThisApp \Classes \SomeClass \Libraries \FooLib 
      ???
    • 我不会因为分类而自责。实际上,我喜欢您目前拥有的一个大列表,我知道大多数其他人更喜欢将事物分组。对我来说,重要的一点是分离项目版本并使用外部结构在硬盘上构建工作副本 - 通过这样做,存储库的确切结构并不重要。
    【解决方案2】:

    这本免费的在线颠覆书提供了几个建议的存储库配置:

    http://svnbook.red-bean.com/

    此页面提供了很好的进一步阅读链接:

    http://svnbook.red-bean.com/en/1.5/svn.tour.importing.html#svn.tour.importing.layout

    关于 SVN 的一个非常好的事情是,在 CVS 中并非如此,那就是在目录中移动非常简单。所以不要感到有压力想出一个“最终”的蝙蝠组织权。做一些有效的事情,玩弄结构直到你更喜欢它。

    还有一点值得一提,SVN 对数据使用了写时复制技术。因此,您可以随时为整个目录制作“svn cp”副本。

    【讨论】:

    • 谢谢,不过我实际上已经看过这本书了。问题是这本书没有解释如何处理依赖关系,即应用程序包括来自 \H* 目录的组件。
    • 您可以使用“externals”拉入存储库的其他部分。 svnbook.red-bean.com/en/1.5/svn.advanced.externals.html 您可能会发现 claudio.cicali.name/post/2005/10/svnexternals-micro-howto 比 SVN 1.5 文档更容易理解。 svn:externals 属性的方便之处在于,一旦在版本化目录上设置了它,使用该目录签出工作副本的每个人都可以从外部定义中受益。
    • 感谢您对外部使用的解释。当我弄清楚如何正确构建我的存储库时,我会尝试它。
    猜你喜欢
    • 2015-05-11
    • 2020-02-28
    • 1970-01-01
    • 2021-10-24
    • 2017-04-20
    • 2022-01-26
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多