您如何组织版本控制存储库?
-
03-07-2019 - |
题
首先,我知道这一点:您将如何为内部软件项目组织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项目(产生单个.dll或单个.exe)
我们计划如何布置存储库。主要问题是,我们有多个解决方案,但我们希望在解决方案之间共享项目。 我们认为将这些共享项目移动到他们自己的解决方案中没有任何意义,相反,我们决定使用svn:externals在解决方案之间共享项目。我们还希望将一组通用工具和第三方库保存在存储库中的一个位置,并使用svn:externals在每个解决方案中引用它们。
您如何看待这种布局?特别是关于svn:externals的使用。这不是一个理想的解决方案,但考虑到所有的利弊,这是我们能想到的最好的解决方案。你会怎么做?
解决方案
如果您按照我的建议(我有多年),您将能够:
- 将每个项目放在源代码管理中的任何位置,只要保留项目根目录下的结构
- 在任何机器上的任何位置构建每个项目,风险最小,准备工作量最小
- 完全独立构建每个项目,只要您可以访问其二进制依赖项(本地“库”和“输出”目录)
- 构建并使用任何项目组合,因为它们是独立的
- 构建并使用单个项目的多个副本/版本,因为它们是独立的
- 避免使用生成的文件或库混乱源控件存储库
我推荐(这是牛肉):
-
定义每个项目以生成单个主要可交付项,例如.DLL,.EXE或.JAR(默认使用Visual Studio)。
-
将每个项目构建为具有单个根目录的目录树。
-
为其根目录中的每个项目创建一个自动构建脚本,该脚本将从头开始构建,并且不依赖于IDE(但如果可行的话,不要阻止它在IDE中构建)。 / p>
-
考虑使用Windows上的nAnt for .NET项目,或者基于您的操作系统,目标平台等的类似项目。
-
使每个项目构建脚本从单个本地共享“库”引用其外部(第三方)依赖项。目录,每个这样的二进制文件由版本完全标识:
%DirLibraryRoot%\ ComponentA-1.2.3.4.dll
,%DirLibraryRoot%\ ComponentB-5.6.7.8.dll
。 -
使每个项目构建脚本将主要可交付成果发布到单个本地共享“输出”。目录:
%DirOutputRoot%\ ProjectA-9.10.11.12.dll
,%DirOutputRoot%\ ProjectB-13.14.15.16.exe
。 -
使每个项目构建脚本通过“库”中的可配置和完全版本化的绝对路径(参见上文)引用其依赖项。和“输出”目录,而不是在哪里。
-
永远不要让项目直接引用另一个项目或其任何内容 - 只允许引用“输出”中的主要交付项。目录(见上文)。
-
通过可配置且完全版本化的绝对路径使每个项目构建脚本引用其所需的构建工具:
%DirToolRoot%\ ToolA \ 1.2.3.4
,%DirToolRoot%\ ToolB \ 5.6.7.8 代码>
-
使每个项目通过相对于项目根目录的绝对路径构建脚本引用源内容:
$ {project.base.dir} / src
,$ {project。 base.dir} / tst
(语法因构建工具而异)。 -
总是要求项目构建脚本通过绝对可配置路径(以可配置变量指定的目录为根)引用每个文件或目录:
$ {project.base.dir} / some / dirs
或$ {env.Variable} / other / dir
。 -
永远不要让项目构建脚本使用相对路径引用ANYTHING,例如
。\ some \ dirs \ here
或.. \ some \ more \ dirs
,总是使用绝对路径。 -
永远不要让项目构建脚本使用没有可配置根目录的绝对路径来引用ANYTHING,例如
C:\ some \ dirs \ here
或\\服务器\共享\更\东西\有代码>
-
对于项目构建脚本引用的每个可配置根目录,请定义将用于这些引用的环境变量。
-
尝试最小化配置每台计算机时必须创建的环境变量数。
-
在每台计算机上,创建一个shell脚本,用于定义必需的环境变量该机器(如果相关,可能特定于该用户)。
-
不要将特定于机器的配置shell脚本放入源代码管理中;相反,对于每个项目,将项目根目录中的脚本副本作为模板提交。
-
要求每个项目构建脚本检查其每个环境变量,如果未定义,则中止有意义的消息。
-
要求每个项目构建脚本检查其依赖的构建工具可执行文件,外部库文件和依赖项目可交付文件,如果这些文件不存在,则使用有意义的消息中止。
-
抵制将任何生成的文件提交到源代码管理中的诱惑 - 没有项目可交付成果,没有生成的源代码,没有生成的文档等。
-
如果您使用IDE,请生成任何项目控制文件,并且不要将它们提交给源代码控制(这包括Visual Studio项目文件)。
-
使用所有外部库和工具的正式副本建立一个服务器,以便在开发人员工作站和构建计算机上进行复制/安装。备份它以及源代码控制存储库。
-
建立一个没有任何开发工具的持续集成服务器(构建机器)。
-
考虑一个管理外部库和可交付成果的工具,例如Ivy(与Ant一起使用)。
-
不要使用Maven - 它最初会让你开心,最终会让你哭泣。
醇>
请注意,这些都不是特定于Subversion的,并且大多数是针对任何操作系统,硬件,平台,语言等的项目的通用。我确实使用了一些操作系统和工具特定的语法,但仅限于为了说明 - 我相信您会转换为您的操作系统或首选工具。
有关Visual Studio解决方案的其他说明:请勿将它们放在源代码管理中!使用这种方法,您根本不需要它们,或者您可以生成它们(就像Visual Studio项目文件一样)。但是,我发现最好将解决方案文件保留给各个开发人员,以便他们认为合适时创建/使用(但没有签入源代码控制)。我在我的工作站上保留了一个 Rob.sln
文件,我从中引用了我当前的项目。由于我的项目都是独立的,我可以随意添加/删除项目(这意味着没有基于项目的依赖项引用)。
请不要使用Subversion外部(或其他类似的工具),它们是反模式,因此是不必要的。
实施持续集成时,或者甚至只想自动执行发布过程时,请为其创建脚本。创建一个shell脚本:获取项目名称的参数(如存储库中列出的)和标记名称,在可配置的根目录中创建一个临时目录,检查给定项目名称和标记名称的来源(通过构造对于该临时目录,在Subversion的情况下适当的URL,执行运行测试并打包交付物的干净构建。此shell脚本应该适用于任何项目,并应作为“构建工具”的一部分检入源代码管理中。项目。您的持续集成服务器可以使用此脚本作为构建项目的基础,或者甚至可以提供它(但您仍可能想要自己的)。
@VonC:你不想随时使用“ant.jar”工作。而不是“ant-a.b.c.d.jar”在你的构建脚本中断后被烧毁,因为你在不知不觉中使用不兼容的Ant版本运行它。这在Ant 1.6.5和1.7.0之间尤为常见。概括,您总是想知道正在使用的每个组件的特定版本,包括您的平台(Java A.B.C.D)和您的构建工具(Ant E.F.G.H)。否则,你最终会遇到一个bug和你的第一个
其他提示
我相信使用Subversion的实用版本控制拥有组织存储库所需的一切。
我们已将我们的设置与您发布的内容完全匹配。我们使用一般形式:
\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控件中,我一直认为他们应该这样做。
为什么要将它全部放在一个存储库中?为什么不为每个项目都有一个单独的存储库(我的意思是“解决方案”)?
好吧,至少我已经习惯了每个项目一个存储库的方法。您的存储库结构似乎过于复杂。
您计划将多少个项目放入这个大型存储库? 2? 3? 10? 100?
当你取消一个项目的开发时你会怎么做?只需从存储库树中删除它,以便将来很难找到它。还是让它永远躺在身边?或者当您想将一个项目完全移动到另一个服务器时?
那些版本号的混乱怎么样?一个项目的版本号如2,10,11,而另一个项目如1,3,4,5,6,7,8,9,12 ......
也许我很愚蠢,但我喜欢每个存储库一个项目。
我认为提出的结构的主要缺点是共享项目只会使用添加的第一个解决方案进行版本控制(除非svn:externals比我想象的更漂亮)。例如,当您为Solution2的第一个版本创建分支时,Project1将不会分支,因为它位于Solution1中。如果您需要稍后从该分支构建(QFE版本),它将在分支时使用最新版本的Project1而不是Project1的版本。
出于这个原因,将共享项目放在一个或多个共享解决方案(以及结构中的顶级目录)中然后随每个任何解决方案的发行版分支它们可能是有利的。
要添加到相对路径问题:
我不确定这是一个问题:
只需在名为“Solution1”的目录下检查Solution1 / trunk,同样解决Solution2:实际表示分支的“目录”的目标是导入工作区后不可见。因此,'Solution1'(实际上是'Solution1 / trunk')和'Solution2'(Solution2 / trunk)之间可能存在相对路径。
RE:相对路径和共享文件问题 -
这似乎是特定的svn,但这不是问题。另一个人已经提到了单独的存储库,这可能是我可以想到的最佳解决方案,在这种情况下,您有不同的项目引用任意其他项目。如果您没有共享文件,那么OP解决方案(以及许多其他解决方案)将正常工作。
我们仍在努力解决这个问题,我现在有三种不同的努力(不同的客户端)我必须立即解决,因为我接手设置了不存在或不良的版本控制。
我有类似的布局,但我的行李箱,树枝,标签一直在顶部。所以:/ trunk / main,/ trunk / utils,/ branches / release /等等。
当我们想要尝试其他版本控制系统时,这最终变得非常方便,因为许多翻译工具最适合基本的教科书SVN布局。