您如何组织版本控制存储库?


108

首先,我知道这一点:您将如何为内部软件项目组织Subversion存储库? 接下来,是一个实际的问题:我的团队正在重组我们的存储库,我正在寻找有关如何组织存储库的提示。(在这种情况下为SVN)。这就是我们想出的。我们有一个存储库,多个项目和多个svn:externals交叉引用

\commonTools /*tools used in all projects. Referenced in each project with svn:externals*/
   \NUnit.v2.4.8
   \NCover.v.1.5.8
   \<other similar tools>
\commonFiles /*settings strong name keys etc.*/
   \ReSharper.settings
   \VisualStudio.settings
\trash /*each member of the team has trash for samples, experiments etc*/
   \user1
   \user2
\projects
   \Solution1 /*Single actual project (Visual Studio Solution)*/
      \trunk
         \src
             \Project1 /*Each sub-project resulting in single .dll or .exe*/
             \Project2
         \lib
         \tools
         \tests
         \Solution1.sln
      \tags
      \branches
   \Solution2
      \trunk
         \src
             \Project3 /*Each sub-project resulting in single .dll or .exe*/
             \Project1 /*Project1 from Solution1 references with svn:externals*/
         \lib
         \tools
         \tests
         \Solution2.sln
      \tags
      \branches

要清除词汇表:解决方案表示单个产品,Project是Visual Studio Project(导致单个.dll或单个.exe)

这就是我们计划布置存储库的方式。主要问题是,我们有多个解决方案,但我们希望在解决方案之间共享项目。我们认为将那些共享的项目移至他们自己的解决方案确实没有意义,而是我们决定使用svn:externals在解决方案之间共享项目。我们还希望将一组通用的工具和第三方库保留在资源库中的某个位置,并在每个解决方案中使用svn:externals对其进行引用。

您如何看待这种布局?特别是关于svn:externals的使用。这不是理想的解决方案,但是考虑到所有利弊,这是我们能想到的最好的解决方案。你会怎么做?


你确定你的意思是“ th打”吗?还是“垃圾”?
ssc 2014年

Answers:


92

如果您遵循以下建议(我已有多年),您将能够:

-将每个项目放在源代码管理中的任何位置,只要您保留下来的项目根目录中的结构

-在任何机器上的任何地方建立每个项目,风险和准备工作最少

-只要可以访问每个项目的二进制依赖项(本地“库”和“输出”目录),就可以完全独立地构建每个项目

-由于项目是独立的,因此可以与任何项目组合进行构建和工作

-构建和使用单个项目的多个副本/版本,因为它们是独立的

-避免使源代码控制存储库中的文件或库混乱

我推荐(这是牛肉):

  1. 定义每个项目以产生单个主要可交付成果,例如.DLL,.EXE或.JAR(Visual Studio默认)。

  2. 将每个项目构建为具有单个根的目录树。

  3. 在其根目录中为每个项目创建一个自动构建脚本,该脚本将从头开始构建它,并且不依赖IDE(但如果可行,请不要阻止在IDE中构建它)。

  4. 考虑在Windows或基于您的操作系统,目标平台等的类似项目中使用.NET项目的nAnt。

  5. 使每个项目构建脚本从单个本地共享“库”目录中引用其外部(第三方)依赖关系,每个这样的二进制文件均由版本FULLY标识: %DirLibraryRoot%\ComponentA-1.2.3.4.dll%DirLibraryRoot%\ComponentB-5.6.7.8.dll

  6. 使每个项目构建脚本将主要交付物发布到单个本地共享的“输出”目录:%DirOutputRoot%\ProjectA-9.10.11.12.dll%DirOutputRoot%\ProjectB-13.14.15.16.exe

  7. 通过“库”和“输出”目录中的可配置且完全版本化的绝对路径(请参见上文),使每个项目构建脚本都引用其依赖项,而在其他地方也没有。

  8. 绝对不要让一个项目直接引用另一个项目或其任何内容,而只能在“输出”目录(请参见上文)中引用主要的可交付成果。

  9. 通过可配置且完全版本化的绝对路径%DirToolRoot%\ToolA\1.2.3.4,使每个项目构建脚本引用其所需的构建工具: ,%DirToolRoot%\ToolB\5.6.7.8

  10. 请以绝对相对于项目的根目录的路径中的每个项目生成脚本引用源内容: ${project.base.dir}/src${project.base.dir}/tst(语法通过构建工具而异)。

  11. 始终需要项目构建脚本通过绝对的可配置路径(以可配置变量指定的目录为根)引用每个文件或目录:${project.base.dir}/some/dirs${env.Variable}/other/dir

  12. 切勿允许项目构建脚本使用诸如.\some\dirs\here或的相对路径引用任何内容..\some\more\dirs,始终使用绝对路径。

  13. 绝对不允许项目构建脚本使用没有可配置根目录的绝对路径(例如C:\some\dirs\here或)引用任何内容\\server\share\more\stuff\there

  14. 对于项目构建脚本引用的每个可配置根目录,定义一个将用于这些引用的环境变量。

  15. 尝试减少必须配置以配置每台计算机的环境变量的数量。

  16. 在每台机器上,创建一个定义必要的环境变量的外壳程序脚本,该脚本是THAT机器特有的(如果相关,可能是该用户的特有)。

  17. 不要将机器特定的配置外壳程序脚本放入源代码管理中;相反,对于每个项目,请在项目根目录中提交脚本的副本作为模板。

  18. 需要每个项目构建脚本来检查其每个环境变量,如果未定义它们,则以有意义的消息中止。

  19. 需要每个项目构建脚本来检查其每个依赖的构建工具可执行文件,外部库文件和依赖的项目可交付文件,如果这些文件不存在,则通过有意义的消息中止。

  20. 抵制将任何生成的文件提交到源代码管理的诱惑-没有项目可交付成果,没有生成的源代码,没有生成的文档等。

  21. 如果使用IDE,请生成任何可能的项目控制文件,并且不要将其提交给源代码管理(包括Visual Studio项目文件)。

  22. 用所有外部库和工具的正式副本建立服务器,以将其复制/安装在开发人员工作站和构建机器上。备份它,以及源代码控制存储库。

  23. 使用任何开发工具都无法建立持续集成服务器(构建机器)。

  24. 考虑一种用于管理外部库和可交付成果的工具,例如Ivy(与Ant一起使用)。

  25. 请勿使用Maven,它最初会使您感到高兴,最终会使您哭泣。

请注意,这些都不是Subversion特有的,并且大多数都针对于针对任何OS,硬件,平台,语言等的项目。我确实使用了一些OS和工具特定的语法,但仅用于说明- -我相信您会转换为您选择的操作系统或工具。

有关Visual Studio解决方案的其他说明:不要将其放在源代码管理中!使用这种方法,您根本不需要它们,也可以生成它们(就像Visual Studio项目文件一样)。但是,我发现最好将解决方案文件留给各个开发人员在他们认为合适的情况下创建/使用(但不要签入源代码管理)。我Rob.sln在工作站上保存了一个文件,从中可以引用我当前的项目。由于我的项目都是独立的,因此我可以随意添加/删除项目(这意味着没有基于项目的依赖项引用)。

请不要使用Subversion外部工具(或其他工具中的类似工具),因为它们是反样式,因此是不必要的。

当您实现持续集成时,或者甚至只是想要自动化发布过程时,请为其创建脚本。制作一个单一的shell脚本,该脚本:获取项目名称(如存储库中所列)和标签名称的参数,在可配置的根目录中创建一个临时目录,为给定的项目名称和标签名称检查源(通过构造(如果是Subversion,则使用适当的URL)到该临时目录,执行干净的构建,该构建运行测试并打包可交付结果。此Shell脚本应可在任何项目上使用,并且应作为“构建工具”项目的一部分检入源代码管理。您的持续集成服务器可以使用此脚本作为构建项目的基础,甚至可以提供此脚本(但您可能仍需要自己的脚本)。

@VonC:当构建脚本被破坏时,由于在不知不觉中使用不兼容的Ant版本运行该脚本时,您不想一直使用“ ant.jar”而不是“ ant-abcdjar”。这在Ant 1.6.5和1.7.0之间特别常见。概括而言,您总是想知道正在使用每个组件的特定版本,包括您的平台(Java ABCD)和构建工具(Ant EFGH)。否则,您最终将遇到错误,并且您的第一个BIG问题将是跟踪涉及到的各个组件的版本。最好事先解决该问题。


6
这么多批评的要点...足以说这不是普遍的食谱!当项目规模很大且第三方的数量很重要时,第5点和第6点特别容易出错:您希望始终使用“ ant.jar”而不是“ ant1.5.4.jar”或产品myProduct进行工作.exe,而不是1.3.exe
VonC

5
不过,对于您提出的许多其他观点,+ 1都是有效的,对于您在该主题上的丰富经验也能给予很高的评价。
VonC

3
我很想听听您的批评并与之互动-每一点都基于解决大型项目的不良经验。例如,解决由Xxx.jar和Yyy.exe表示哪个版本的问题,尤其是当确实引用了十几个副本时。
罗布·威廉姆斯

2
@Rob-您能否详细说明“外部反模式”主题?我提出它作为一个问题在这里:stackoverflow.com/questions/338824/...

3
@Makis:如果#12与#13之间没有平衡,那您是正确的。每个项目中对文件或目录的每次引用都应通过以可配置的根目录变量(例如,Ant中的$ {basedir} /sub/dir/file.txt)开头的绝对路径进行。
罗布·威廉姆斯,2009年


3

我们已将其设置为几乎与您发布的内容完全匹配。我们使用一般形式:

\Project1
   \Development (for active dev - what you've called "Trunk", containing everything about a project)
   \Branches (For older, still-evolving supported branches of the code)
       \Version1
       \Version1.1
       \Version2
   \Documentation (For any accompanying documents that aren't version-specific

尽管我认为不如您的示例那么完整,但它对我们来说效果很好,并且让我们分开了。我喜欢每个用户也有一个“ Thrash”文件夹的想法-当前,这些类型的项目并没有最终出现在Source control中,我一直觉得应该这样做。


3
令您感到惊讶的是,您有一个单独的目录,用于存放版本之间不会更改的文档……我从来没有感到过开发这种产品的乐趣!:)
ARKBAN

1

为什么要全部放在一个存储库中?为什么不为每个项目都拥有单独的存储库(我的意思是“解决方案”)?

好吧,至少我已经习惯了每个存储库一个项目的方法。您的存储库结构对我来说似乎过于复杂。

您打算将多少个项目放入这个大仓库中?2?3?10个?100?

当您取消一个项目的开发时,您会怎么做?只需将其从存储库树中删除,以便将来很难找到它。还是让它永远躺在身边?或者,当您要将一个项目完全移至另一台服务器时?

那所有这些版本号怎么办?一个项目的版本号类似于2,10,11,而另一个项目的版本号类似于1,3,4,4,5,6,7,8,9,12 ...

也许我很愚蠢,但是我喜欢每个存储库一个项目。


1.一个存储库是公司政策,不能更改。2.我们将提供大约十二种解决方案。3.按版本号表示修订?这对我们来说不是问题。
Krzysztof Kozmic

一个好的项目结构应该忽略其余的存储库结构,尤其是对于一个或多个存储库。请参阅我的详细答案。
罗伯·威廉姆斯

1
请注意,在许多(大多数?)源代码控制工具中拥有多个存储库可能非常昂贵,例如在实现安全性时。
罗布·威廉姆斯

0

我认为所提议结构的主要缺点是,共享项目将仅使用添加了它们的第一个解决方案进行版本控制(除非svn:externals比我想象的更奇特)。例如,当您为解决方案2的第一个版本创建分支时,Project1将不会被分支,因为它位于解决方案1中。如果您需要在以后的时间(QFE版本)从该分支进行构建,它将使用最新版本的Project1,而不是分支时的Project1版本。

因此,将共享项目放在一个或多个共享解决方案中(以及结构中的顶级目录),然后将其随任何解决方案的每个发行版一起分支可能是有利的。


你在某种程度上是对的。但是我们可以根据需要更新参考。将共享项目放入自己的解决方案中也没有太大意义。尽管我很想找到比svn:externals更好的解决方案。
Krzysztof Kozmic

“如果需要,请更新参考”是什么意思?我看不到如何在不分支Solution1的情况下分支Project1(似乎在每次分支Solution2时都希望如此)。
C. Dragon 76

请查看我的详细答案,特别是不要将Visual Studio解决方案放入源代码管理中。
罗布·威廉姆斯

0

要添加到相对路径问题:

我不确定这是不是一个问题:
只需在名为“ Solution1”的目录下签出Solution1 / trunk,然后再对Solution2进行检查:实际上,表示分支的“目录”的目标一旦导入到工作区中就不会可见。因此,“ Solution1”(实际上是“ Solution1 / trunk”)和“ Solution2”(Solution2 / trunk)之间的相对路径是可能的。


这很容易破坏,请参阅我的详细答案。
罗布·威廉姆斯

0

RE:相对路径和共享文件问题-

看来这是svn特有的,但这不是问题。另一个人已经提到了单独的存储库,在您有不同的项目引用任意其他项目的情况下,这可能是我能想到的最佳解决方案。在没有共享文件的情况下,OP解决方案(以及许多其他解决方案)将可以正常工作。

自从我接管了不存在的版本控制或不良的版本控制以来,我现在必须解决3个不同的工作(不同的客户端)。


让项目引用其他项目会造成维护的噩梦,因为依赖关系成倍增长,并且引用非常脆弱。请参阅我的详细答案。
罗布·威廉姆斯

0

我有类似的布局,但是我的树干,树枝,标签一直在顶部。因此:/ trunk / main,/ trunk / utils,/ branches / release /等。

当我们想尝试其他版本控制系统时,这实际上非常方便,因为许多翻译工具与基本教科书SVN布局一起使用效果最佳。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.