SVN最佳实践-团队协作

99

我刚开始使用SVN。 我知道基本命令并理解基本原则。 我想知道在团队环境中使用Subversion的任何提示或最佳实践。

我可以看到提交代码时添加合理且详细的消息的好处,但是还有其他需要注意的事项吗?

感谢所有出色的答案-它们帮了很大的忙。

21个回答

77

鼓励频繁提交代码。 对于刚接触版本控制的团队成员来说,他们可能认为需要将代码保留在代码库之外直到“完全可用”。教导大家早期和经常性地提交代码以便尽早发现问题。建议你的团队针对可能破坏主干的特性创建分支而非等到满意后再提交代码。

确立分支和标记管理规范。 除了为新功能建立分支,还可以鼓励团队使用分支进行业务级别的大型修复。在工作开头和结尾设置重要bug修复的标记。维护生产/质量保证发布的标记(可能包括分支)。

确立主干管理策略并严格执行。 例如,“主干必须始终无错误构建”或“主干必须始终通过所有单元测试”。任何无法满足主干标准的工作都必须在分支中完成。


1
分支和合并在SVN中有些麻烦。其他版本控制系统处理得更好,但我从不主张在SVN中采用分支密集的流程。 - Branan
7
@Branan 错了。这是因为你不知道如何正确使用源代码控制。当你分支时,你被期望作为一个好的开发人员,从主干更新你的分支并将最新的更改从主干合并到你的分支中,每天或者几次一天(由你选择),这样最终你就不会遇到积累的合并问题。我本地至少有4-5个分支在进行中,但从来没有像人们所说的那样成为噩梦,因为我做对了...经常更新它以便拥有人们检查到主干并根据其添加代码的变化。 - PositiveGuy

67

不要在代码更改中提交格式更改

如果您想重构巨大文件的空格(Control+K+D),可以。 请将格式更改与实际逻辑更改分开提交。 同样,如果您想在文件中移动函数,请单独提交移动操作而不是与实际编辑混为一谈。


2
我整天编辑一个文件,现在是提交的时候了,如何将格式分离出来? - Dustin Getz
24
如果你打算对已有的代码进行格式更改,那么需要先进行更改、提交,然后再添加新代码/编辑代码。或者是先添加/编辑,提交后再进行格式更改。这样,在添加/编辑的差异上就能够很好地反映出实际修改的内容,而不是简单地显示“现在所有东西都不同了!”的情况。 - lc.
1
+1. 不必要的更改会增加审查相关更改所需的工作量。同时也会使合并/移植更改(例如到不同的分支)变得更加困难。 - Ates Goral
2
虽然这是一个好的实践,但我认为没有人能够强制执行这个。Jason是正确的,一个好的开发者会意识到他们可以使用一个好的diff工具(其中一个内置于tortoise SVN中)来忽略空格以过滤掉噪音。 - Ken Sykora
2
这可以通过代码审查和对团队成员的教育来实施。我认为将逻辑更改与代码更改分开不应该成为审核者的负担,而应该是实施者的责任。 - Marquez

44

我始终坚持的一个关键概念是一起提交相关代码更改。其对应原则是不要在同一个提交中提交无关的代码更改。这意味着不要在一个提交中修复2个错误(除非是相同的修复),也不要在两个提交的每个提交中都提交一半的错误修复。另外,如果我需要为系统的一个不相关部分添加一些新的增强功能或其他内容,然后我需要为其他工作做准备,我会先单独提交增强功能。这个想法是,任何人可能想要单独拥有或回滚的任何更改都应该是单独的提交。当进行合并或回滚失败的功能时,这将为您节省大量头疼。


4
+1。当你提交代码时,这似乎很麻烦。但是,当你回顾旧代码时,一个充满原子提交的仓库是无价的。 - Gordon Wilson
2
这不是特性分支的作用吗?在特性分支上进行尽可能多的提交,当准备好时将其合并到主干上...回滚只意味着删除已合并的提交。保持相关代码在一起加1分... - farinspace

18

已经提到了很多内容,以下是更多的建议:

  1. 如果你有不想放在源代码控制下的文件(例如配置文件、编译文件等),将它们添加到忽略列表中。这样,通过始终期望未知文件列表为空,您可以注意到任何您忘记添加的文件。

  2. 添加一个提交后事件发送电子邮件到开发者邮件列表(或专门用于此目标)相关提交的更改和最好包含其补丁。

  3. 与您的缺陷跟踪器集成,以便提交引用显示在缺陷/功能请求上,并带有指向差异的链接。像 MantisBT 这样的缺陷跟踪器支持此功能。

  4. 考虑与持续集成(例如 CruiseControl.NET)、NAnt 用于构建以及 NUnit/VS 用于单元测试进行集成。这样,一旦用户提交代码或在计划的时间间隔内,就会编译代码、运行单元测试,并向开发人员反馈该过程的信息。这也将提醒团队其他成员,如果存储库已损坏(即无法构建)。


我们的做法是将所有配置文件的扩展名更改为config.php.config或类似的方式,这样我们可以将配置文件保存在服务器上,但每个团队成员都有自己的副本。当配置文件发生重大更改时,我们从svn版本中复制一个副本... - zidane

15

基础操作:

  • 在对版本进行QA之前创建标签。
  • 在进行风险更改(例如大规模重构)之前创建标签。
  • 为发布的版本创建分支,以便冻结代码。
  • 确保人们知道在开始编写代码之前更新,并在提交之前再次更新。
  • SVN允许不同用户对同一文件进行多个检出。确保每个人解决可能出现的任何冲突。
  • 永远不要将同一个SVN帐户用于多个用户。这可能会导致可怕的结果。

8
我用相反的方式处理分支和标签。分支是从主干派生的,最终将与主干合并。标签用于冻结代码。 - steve_c
1
分支是可以更改的副本。标签是不应更改的副本。http://svnbook.red-bean.com/en/1.2/svn.branchmerge.tags.html - matpie
我也做类似的事情。当我将代码发布到QA或生产环境时,我会打标签并创建分支。这样,我们就有了一个只读标记以及一个分支来解决该版本的错误修复,而不会影响主干上可能进行的新功能开发。 - JamesEggers
Svn还允许同一用户对同一文件夹进行多次检出。因此,如果您发现需要进行与当前工作无关的更改(例如某个客户要求紧急修复或您偶然发现一个完全不相关的错误),请再次检出并单独修复它。 - PMF
应该使用“标签”来进行代码冻结。如果您尝试更改“标签”分支,您的SVN客户端甚至会发出警告。 - Danijel

12
人们提供的答案很好。这些内容大部分都可以在svn用户文档的最佳实践中找到总结。
重申一下:
  1. 建立你的仓库结构(应该有项目根目录,其中包含主干、分支和标签)
  2. 选择你的分支策略(私有分支、按里程碑/发布/错误分类的分支等),并坚持执行 -- 我建议尽可能多地创建分支,但不需要私有分支
  3. 选择你的标记策略-- 标记越多越好,但最重要的是确定你的标记命名约定
  4. 选择你提交到主干的策略--保持主干尽可能“干净”,它应该随时可以发布。

这是一个相当古老的最佳实践,因此我认为CollabNet不再推荐它们。是否有任何新的最佳实践可用?你提到的那个归属于SVN 1.0的时代。 - mliebelt
1
@mliebelt - 我已经更新了 Apache 版本的链接。无论年龄如何,选择你的 repo 结构、分支策略、标签策略和主干提交策略的想法以及上面的很好的回答仍然是可靠的。 - hromanko
“Branch-When-Needed系统”的描述相当疯狂。听起来像是一场办公室枪击案的配方。 - naught101

12

我想总结一下我坚持的最佳实践:

  1. 不要提交二进制文件。应该有单独的仓库用于存放二进制文件,比如 NexusIvyArtifactory
  2. 应该有仓库结构。个人使用以下仓库结构:

    /trunk
    /tags
        /builds
            /PA
            /A
            /B
        /releases
            /AR
            /BR
            /RC
            /ST
    /branches
        /experimental
        /maintenance
            /versions
            /platforms
        /releases
    
    • 使用特定的分支类型列表,如下:experimental(实验)、maintenance(维护)、versions(版本)、platforms(平台)、releases(发布)。
    • 使用特定的标签类型:PA(预-α)、A(α)、B(β)、AR(α-发布)、BR(β-发布)、RC(发行候选)、ST(稳定)。
    • 最小化合并的必要性。应该制定规则来确定何时可以/鼓励合并以及何时不行。
    • 版本编号。应该采用一种已建立的版本编号方法。通常这在软件配置管理计划等高级项目文档中描述。我个人使用复杂的版本编号方法。按照这种方法,版本具有以下模式:N.x.x(维护/支持分支)、N.M.x(发行分支)、N.x.K(构建)、N.M.K(发布)。
    • 尽可能经常提交。如果很难(例如,需要进行太多更改才能实现功能甚至编译代码),则应该使用实验分支。
    • 主干应包含最新的开发内容。例如,当在trunk或branch中选择在哪里开发应用程序的新主要版本(N.x.x)时,决策应始终有利于trunk。旧版本应分支到maintenance/support分支。这假定存在主要版本及其特定内容(架构、兼容性),并尽早出现。
    • strict '不破坏版本' 政策适用于release分支。同时,对于trunk来说,只要它可能具有实验性开发或需要解决合并问题的代码库,就不一定严格执行该政策。
    • 使用svn:externals。这将允许模块化项目,建立透明的发布管理流程,并在不同的功能之间进行划分和治理。
    • 使用问题跟踪。您将能够在提交消息中指出问题参考。
    • 禁用空提交消息。可以使用pre-commit hooks完成。
    • 定义要持续集成的分支。例如,我喜欢为trunk、maintenance和release分支使用持续集成。
    • 为不同类型的分支制定持续集成政策。正如我前面所指出的,最严格的“不破坏版本”规则适用于发布分支,而对于trunk和maintenance分支,有时可能会出现故障。此外,在trunk/maintenance和release分支上运行的检查列表之间存在差异。

    您可以在以下形式的图表中找到我使用的软件配置管理方法的主要原则概述。


1
那么,你是如何在团队中工作的呢?不同的人使用不同的分支吗?如何避免冲突?你的回答没有涉及团队合作 :( - DataGreed
3
Q: 如何避免冲突? A: 尽量减少合并的必要性主干应包含最新的开发内容尽可能频繁地提交修改Q: 不同的人使用不同的分支吗? A: 每个分支可以由一个或多个人使用。区分分支类型也很重要:实验、维护和发布,这有助于避免冲突。Q: 你的回答没有涉及团队合作。 A: 虽然看起来可能是这样。使用版本控制自动意味着团队合作。我描述了一组规则(作为道路规则),这些规则有助于更有效地协作。 - altern
我对SVN不太熟悉,我知道这是一个老问题,但在2021年我仍然有一个问题。既然Trunk和tags也可以有发布版本,为什么还需要发布分支?是否真的有必要拥有一个发布分支(或多个)?提前致谢。 - Juan Ignacio Avendaño Huergo
1
@JuanIgnacioAvendañoHuergo:发布分支的作用是将正在进行的开发隔离在主干中(最有可能包含功能提交),以便在不接受功能提交的情况下稳定发布并修复错误。 - altern

7
我发现非常有用的一件事是svn:external属性,它意味着你可以将其他存储库中的目录引用到自己的存储库中。这给代码和数据的组织提供了非常好的方式。以下是一些例子:
  1. 如果你有不同模块/库的单独存储库并引用正在使用的存储库,那么你可以为每个可执行文件拥有一个元存储库。如果它是仅使用少数模块的小型可执行文件,则无需检出整个树。这样做的结果是你可以获得每个模块的SVN修订号。
  2. 将大型二进制数据(例如库的编译版本)添加到代码存储库通常被认为是不好的习惯,但它确实非常方便。如果你只是将使用的所有库的所有版本添加到另一个存储库中,你可以获得两个世界的最佳体验。你将所使用的库的版本引用到代码存储库中。当检出代码存储库时,你将同时获得代码和二进制文件。然而,二进制文件存储在一个大型存储库中,你不需要像备份源代码存储库那样严格备份它,并且源代码存储库保持小型且仅包含文本。

1
我喜欢第二点。由于在使用svn:external时可以指定修订版本号或不指定,这将允许您将某些库固定到特定版本,同时允许其他库“跟踪”最新版本。 - j_random_hacker
使用“svn:external”是SVN中最强大、最基本的功能之一。它是必不可少的。 - Danijel

5

与您的缺陷跟踪软件进行集成。如果您使用Bugzilla,则可以设置它,以便如果您的评论以“Bug XXXX”开头,则您的SVN评论会自动添加为该缺陷的评论,包括指向该修订版本的SVN Web界面的链接。


Trac在缺陷跟踪方面具有良好的svn集成,此外还包括时间轴、提交差异、维基等功能。 - Doug Currie
Jira还跟踪与问题相关的提交。 - Dan Soap

4
了解SVN的分支和合并工具及惯例。
与团队成员合作的最佳方式是将工作分为完整的开发功能/修复,然后在一个分支中对每个更改进行单独处理。完成/准备好合并时,再将更改合并回主干分支/主线分支。
这样,个人可以在不与其他更改产生冲突的情况下朝着共同目标(在同一分支或不同分支上)努力工作。
您的实际情况可能有所不同,并且对于只有两个人左右的小团队来说可能过于繁琐。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接