关于svn:版本控制中的项目结构

关于svn:版本控制中的项目结构

Structure of Projects in Version Control

我知道在版本控制中至少有10种不同的方式来构造项目。 我很好奇正在使用的某些方法以及哪种方法对您有用。 我曾经使用SVN,TFS和当前/不幸的是VSS。 我已经看到版本控制的执行效果很差,虽然还可以,但是从来没有很好。

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

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

  • 分支属于站点的单个项目
    / division / web / projectName / vb / src / [trunk |分支|标签]

  • 分支整个站点,就我所知,分支到整个站点,除了核心组件。
    / div // [trunk | branch | tags] / web / projectName / vb / src /

  • 使用main-line作为默认选项,仅在必要时才进行巨大更改。


  • 我们使用Java进行高度组件化的开发,我们的主干中有大约250个具有独立生命周期的模块。依赖关系是通过Maven管理的(这是最佳实践),每次(每两周一次)主动开发的模块都会使用新版本进行标记。具有严格语义的3位版本号(major.minor.build-重大更改表示向后不兼容,较小更改表示向后兼容,而内部版本号更改表示向后和向前兼容)。我们最终的软件产品是一个装配体,该装配体引入了数十个单独的模块,再次作为Maven依赖项。

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

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

    我们大致执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    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决定了结构,因此可以在这里提供帮助。只要您坚持使用许多结构,就可以了。


    SVN示例:

    树干/

    科/

    标签/

    行李箱应保持在可以随时从其推出释放物的位置。您应该没有应该知道的巨大的bug(当然最终会出现,但这是您应该努力的目标)。

    每当您需要制作新功能时,都可以进行设计更改(无论分支如何)。在开始时标记该分支。然后,在完成分支标记后,将其结尾。这有助于合并回主干。

    每次需要发布时,请标记。这样,如果出现严重错误,则可以回滚到以前的版本。

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

    编辑:对于第三方的东西,这取决于。如果我可以避免它,那么我就不在源代码控制之下。我将其保存在源代码管理外部的目录中,并从那里包含它。对于诸如jquery之类的事情,我的确将其置于源代码控制之下。原因是它简化了我的推脚本。我可以简单地让它执行svn导出和rsync。


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

    • trunk

      • config
      • docs
      • sql

        • initial
        • updates
      • src

        • app
        • test
      • thirdparty

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

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


    我更喜欢粒度细,组织性强,自包含的结构化存储库。有一个图说明了存储库维护过程的一般(理想)方法。例如,我的存储库的初始结构(每个项目存储库都应具有)是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /project
        /trunk
        /tags
            /builds
                /PA
                /A
                /B
            /releases
                /AR
                /BR
                /RC
                /ST
        /branches
            /experimental
            /maintenance
                /versions
                /platforms
            /releases

    PA表示前字母
    A表示字母
    B表示beta
    AR表示alpha释放
    BR表示Beta版本
    RC表示候选发布
    ST表示稳定

    内部版本和发行版本之间存在差异。

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

    最近,我开发了专门用于软件配置管理的培训,其中描述了版本编号方法以及为什么该存储库结构确切是最好的。这是演示幻灯片。

    关于"多个SVN存储库与单个公司存储库"的问题,我也有答案。只要您解决问题中存储库结构的这一方面,它就可能会有所帮助。


    由于我们将所有工件和构造都放在同一棵树中,因此我们具有以下内容:

    • 树干

      • 规划与跟踪
      • 要求
      • 设计
      • 施工

        • 箱子
        • 数据库
        • 解放
        • 资源
    • 部署

    • 质量检查

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

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


    What about external dependencies such a the AJAXTookit or some other 3rd party extension that's used on several projects?

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


    我认为,团队采用的SCM政策和程序将非常取决于他们使用的开发过程。如果您有一个由50人组成的团队,同时有几个人同时从事主要变更,并且仅每6个月发布一次,那么每个人都有自己的分支机构可以独立工作并且只能合并变更其他人想要的时候。另一方面,如果您是一个由5人组成的团队,他们都坐在同一个房间里,那么减少分支的频率就很有意义。

    假设您在一个小型团队中工作,该团队的沟通与协作良好,并且发布频繁,那么对IMO分支机构几乎没有任何意义。在一个项目中,我们仅将SVN修订号滚动到所有发行版的产品版本号中,甚至从未标记过。万一在产品中发现一个严重的错误,我们将直接从发布的版本中分支出来。但是大多数时候,我们只是简单地修复了分支中的错误,并按计划在本周末从主干中释放了该错误。如果您的发布频率足够高,那么您几乎永远不会遇到无法等到下一个正式版本的错误。

    我参与了其他项目,但我们从来都无法避免这种情况,但是由于轻量级开发过程和低级的仪式,我们能够非常有效地使用轻量级版本控制策略。

    我还要提到的是,我编写的所有内容都来自企业IT上下文,在该上下文中,给定代码库只有一个生产实例。如果我正在开发一种产品,该产品已在100个不同的客户站点上部署,则分支和标记实践必须更加费劲一些,以便管理所有实例之间的所有独立更新周期。


    在切换到SVN之前,我们从拥有一个大型存储库(超过4G)的VSS的坏世界中迁移出来。我真的很难为我们公司建立新的存储库。我们公司是非常"老"的学校。变革很难,我是年轻的开发人员之一,今年45岁!我是公司开发团队的成员,该团队负责公司多个部门的计划。无论如何,我这样设置目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    + devroot
        +--Dept1
            +--Dept1Proj1
            +--Dept2Proj2
        +--Dept2
            +--Dept2Proj1
        +--Tools
            +--Purchase3rdPartyTools
            +--NLog
            +--CustomBuiltLibrary

    我想包括分支功能,但老实说,在这一点上太过分了。使用此方案,我们仍然遇到一些麻烦。

    • 如果您要进行主要产品升级,则很难解决生产问题(即因为我们不进行分支)
    • 从" Dev"升级到" Prod"的概念很难管理。 (甚至不用问升级为质量检查人员)

    推荐阅读