【问题标题】:Structure of Projects in Version Control版本控制中的项目结构
【发布时间】:2010-09-06 05:17:16
【问题描述】:

我知道在版本控制中至少有 10 种不同的方式来构建项目。我很好奇正在使用哪些方法以及哪些方法适合您。我曾使用过 SVN、TFS 和目前/不幸的是 VSS。我看到版本控制实施得非常糟糕,还不错,但从来都不是很好。

为了让事情顺利进行,这里是对我所见事物的回顾。

此示例基于 SVN,但适用于大多数 VCS(对分布式版本控制不太适用)。

  1. 对属于站点的各个项目进行分支 /division/web/projectName/vb/src/[trunk|branches|tags]

  2. 分支整个站点,在我看到的情况下,除了核心组件之外的整个站点都被分支了。 /division/[trunk|branches|tags]/web/projectName/vb/src/

  3. 默认使用主线,仅在需要巨大更改时分支。

【问题讨论】:

  • 请添加标签"svn",让 git 用户感到困惑。
  • @hhh 我添加了关于分布式版本控制(DVC)的评论。也许关于 DVC 中结构的答案会对某人有所帮助?

标签: svn version-control tfs branch project-structure


【解决方案1】:

我们使用 Java 进行高度组件化的开发,我们在主干中有大约 250 个具有独立生命周期的模块。依赖项是通过 Maven 管理的(这是一个最佳实践),每次迭代(每两周一次)积极开发的模块都会被标记为新版本。具有严格语义的 3 位版本号(major.minor.build - 主要更改意味着向后不兼容,次要更改意味着向后兼容,内部版本号更改意味着向后和向前兼容)。我们的终极软件产品是一个包含数十个单独模块的程序集,同样作为 Maven 依赖项。

当我们需要对已发布版本进行错误修复或增强并且我们无法交付 HEAD 版本时,我们会分支模块/程序集。标记所有版本后,这很容易做到,但分支仍然会产生大量的管理开销(特别是使分支与某些 HEAD 变更集保持同步),这部分是由我们的工具造成的,Subversion 不是管理分支的最佳选择。

我们发现存储库中一个相当平坦且最重要的是可预测的树结构至关重要。它使我们能够构建发布工具,从而消除手动发布过程中的许多痛苦和危险(更新的发布说明、项目编译、运行单元测试、制作标签、无 SNAPSHOT 依赖项等)。避免在树形结构中放置过多的分类或其他逻辑。

我们大致做了如下的事情:

svnrepo/
  trunk/
    modules/
      m1/ --> will result in jar file
      m2/
      ...
    assemblies/
      a1/
      ...
  tags/
    modules/
      m1/
        1.0.0/
        1.0.1/
        1.1.0/
       m2/
      ...
    assemblies/
      a1/
        iteration-55/
        ...
  branches/
    m1/
      1.0/
      ...

对于外部依赖项,我不能过分强调 Maven 之类的东西:将依赖项管理为对存储库中版本化、唯一标识的二进制工件的引用。

对于内部模块/项目结构:坚持标准。一致性是关键。同样,Maven 在这里可以提供帮助,因为它规定了一个结构。许多结构都很好,只要你坚持下去。

【讨论】:

  • .NET 中是否存在类似 maven 的东西?我一直无法发掘任何东西。
  • NMaven 专门针对 .NET (codeplex.com/nmaven),我自己没有使用过。在工作中,我们有使用普通 Maven 和一些 Visual Studio 包装插件构建的 .NET 代码。
  • 我们正在启动一个与您的结构相似的新项目,这看起来是一个好的开始 :) 出于好奇,您有共享的父 pom 吗?如果是这样,您是将父 pom 放在“modules”目录中还是作为“modules”中的实际目录?
  • 我们有一个父 pom 的层次结构,我们像对待模块一样对待它们:它们在模块中都有自己的“模块”目录。由于 Maven2,这最终完全可能,因为父 pom 是通过存储库继承的。在 Maven1 中,您实际上必须使用相对路径,这变得很讨厌。
  • 谢谢 :D 如果您不介意,再问一个问题。我们现在不得不做一些模块重命名(不恰当的初始名称),我们有一点争论。如果说,你的“trunk/modules/m1”需要重命名为“trunk/modules/m10”,你认为“tags/modules/m1”应该重命名为“tags/modules/m10”还是应该“tags /modules/m1" 被保留并创建一个新的 "tags/modules/m10"?
【解决方案2】:

SVN 示例:

主干/

分支/

标签/

后备箱应保持在您可以随时从中推送释放的位置。不应该有你知道的巨大的漏洞(当然最终会有,但这是你应该努力的)。

每当您需要制作新功能时,请进行设计更改,无论如何,分支。在开始时标记该分支。然后,当您完成分支标签时,它会在最后。这有助于合并回主干。

每次你需要推送一个版本,标记。这样,如果出现严重错误,您可以回滚到以前的版本。

此设置使主干尽可能保持清洁,并允许您快速修复错误并将其推出,同时将大部分开发工作保留在分支中。

编辑:对于第 3 方的东西,这取决于。如果我能避免它,我就没有它在源代码控制之下。我将它保存在源代码控制之外的目录中并从那里包含它。对于 jquery 之类的东西,我确实将其置于源代码控制之下。原因是它简化了我的推送脚本。我可以简单地让它做一个 svn 导出和 rsync。

【讨论】:

    【解决方案3】:

    对于我的项目,我总是使用这种结构。

    • 后备箱
      • 配置
      • 文档
      • sql
        • 初始
        • 更新
        • 应用程序
        • 测试
      • 第三方
        • 工具
    • 标签
    • 分支机构
    • config - 用于存储我的应用程序配置模板。在构建过程中,我使用这些模板并将令牌占位符替换为实际值,具体取决于我正在构建的配置。
    • docs - 任何应用程序文档都放在此处。
    • sql - 我将我的 sql 脚本分成两个目录。一个用于您刚开始时的初始数据库设置,另一个用于根据数据库版本号运行的更新脚本。
    • src - 应用程序源文件。在这里,我根据应用程序和测试来分解源文件。
    • thirdparty - 这是我将我在应用程序中引用的第三方库放在 GAC 中不可用的地方。我根据库和工具将它们分开。 lib 目录包含需要包含在实际应用程序中的库。 tools 目录包含我的应用程序引用的库,但仅用于运行单元测试和编译应用程序。

    我的解决方案文件与我的构建文件一起放置在主干目录下。

    【讨论】:

    • 你如何分支?如果您只分支 src 文件夹,您如何处理指向旧版本第三方/lib 的分支?
    【解决方案4】:

    我可以理解不将二进制文件放入存储库的逻辑,但我认为也有一个巨大的优势。如果您希望能够从过去提取特定修订版(通常是较旧的标签),我希望能够从 svn checkout 中获得所需的一切。当然,这不包括 Visual Studio 或 .NET 框架,但拥有正确版本的 nant、nunit、log4net 等可以让从结账到构建变得非常容易。这种上手方式就像“svn co project”后跟“nant build”一样简单。

    我们要做的一件事是将第三方二进制文件放在一个单独的树中,并使用 svn:external 为其提供我们需要的版本。为了让生活更轻松,我们将为每个使用过的版本创建一个文件夹。例如,我们可能会将 ThirdParty/Castle/v1.0.3 文件夹引入当前项目。这样,构建/测试产品所需的一切都在项目根目录内部或之下。根据我们的经验,磁盘空间的折衷是非常值得的。

    【讨论】:

      【解决方案5】:

      由于我们在同一棵树中拥有所有工件和构造,因此我们有如下内容:

      • 主干

        • 规划与跟踪
        • 要求
        • 设计
        • 建筑
          • 数据库
          • 来源
      • 部署

      • 质量检查

      【讨论】:

      • 为什么要降价?即使它不是您看到的标准版本之一,它也似乎是一个不错的结构。
      【解决方案6】:

      我更喜欢细粒度、非常有条理、自包含、结构化的存储库。有一个diagram 说明了存储库维护过程的一般(理想)方法。例如,我最初的存储库结构(每个项目存储库都应该有)是:

      /project
          /trunk
          /tags
              /builds
                  /PA
                  /A
                  /B
              /releases
                  /AR
                  /BR
                  /RC
                  /ST
          /branches
              /experimental
              /maintenance
                  /versions
                  /platforms
              /releases
      

      PA 表示 pre-alpha A 表示 alpha B 表示 测试版 AR 表示 alpha-release BR 表示 测试版 RC 表示候选发布版 ST 表示稳定

      buildsreleases 之间存在差异。

      • builds 文件夹下的标签具有对应模式 N.x.K 的版本号,其中 NK 是整数。示例:1.x.05.x.110.x.33
      • releases 文件夹下的标签具有对应模式 N.M.K 的版本号,其中 NMK 是整数。示例:1.0.05.3.110.22.33

      最近我开发了专门针对软件配置管理的培训,我在其中描述了版本编号方法以及为什么这个存储库结构是最好的。这里是presentation slides

      question 上还有我的answer 关于“多个SVN 存储库与单个公司存储库”。只要您在问题中解决存储库结构的这方面问题,它可能会有所帮助。

      【讨论】:

      • 能否更新第一段中图表的链接?
      【解决方案7】:

      我认为团队采用的 SCM 政策和程序将非常依赖于他们使用的开发过程。如果你有一个 50 人的团队,有几个人同时进行重大更改,并且每 6 个月才发布一次,那么每个人都有自己的分支是很有意义的,他可以在其中独立工作并且只合并来自当他想要其他人时。另一方面,如果你是一个 5 人的团队,所有人都坐在同一个房间里,那么减少分支的频率是有意义的。

      假设您在一个沟通和协作良好且发布频繁的小团队中工作,那么在 IMO 中建立分支几乎没有意义。在一个项目中,我们只是简单地将 SVN 修订号添加到我们所有版本的产品版本号中,我们甚至从未标记。在极少数情况下,在 prod 中发现严重错误,我们会直接从已发布的修订版中直接分支。但大多数时候我们只是简单地修复了分支中的错误,并按计划在周末从主干发布。如果您的发布频率足够高,您几乎永远不会遇到不能等到下一个正式发布的错误。

      我曾参与过其他我们永远无法摆脱的项目,但由于轻量级开发过程和低仪式性,我们能够非常有效地使用轻量级版本控制策略。

      我还要提到,我编写的所有内容都来自企业 IT 环境,其中给定代码库只有一个生产实例。如果我正在开发一个部署在 100 个不同客户站点的产品,那么分支和标记实践必须更加费力,以便管理所有实例中的所有独立更新周期。

      【讨论】:

        【解决方案8】:

        外部依赖项(例如 AJAXTookit 或用于多个项目的其他一些第三方扩展)呢?

        源代码控制用于源代码,而不是二进制文件。将任何 3rd 方程序集/jar 保存在单独的存储库中。如果您在 Java 世界中工作,请尝试使用 Maven 或 Ivy。对于 .Net 项目,只要您对如何构建和更新它有适当的政策,一个简单的共享驱动器就可以很好地工作。

        【讨论】:

          【解决方案9】:

          在切换到 SVN 之前,我们使用一个巨大的存储库(超过 4G)从 VSS 的糟糕世界中迁移出来。我真的很纠结如何为我们公司设置新的存储库。我们公司是很“老”的学校。很难得到改变我是年轻的开发者之一,我已经 45 岁了!我是公司开发团队的一员,该团队为我们公司的多个部门开展项目。反正我是这样设置目录的

          + devroot
              +--Dept1
                  +--Dept1Proj1
                  +--Dept2Proj2
              +--Dept2
                  +--Dept2Proj1
              +--Tools
                  +--Purchase3rdPartyTools
                  +--NLog
                  +--CustomBuiltLibrary
          

          我想加入分支的能力,但老实说,目前这太过分了。使用这个方案我们仍然在努力解决一些问题。

          • 如果您正在进行重大产品升级(即因为我们不进行分支),则很难解决生产问题
          • 很难管理从“Dev”到“Prod”的提升概念。 (甚至不要询问是否要升职为 QA)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-30
            • 2021-03-25
            • 1970-01-01
            • 1970-01-01
            • 2011-10-15
            • 2010-11-30
            • 2011-09-01
            • 1970-01-01
            相关资源
            最近更新 更多