版本控制最佳实践

26

我前几天刚刚开始使用版本控制,由于在Subversion上的不好经历,我转向了Mercurial,并且目前感到很满意。

虽然我理解和赞赏版本控制的想法,但我实际上并没有任何经验。

现在,我正在为我正在开发的一些网站使用它,然后有几个问题浮现出来:

  • 我应该什么时候/多久提交?是否在任何重大更改之后(无论是否有效)?当我完成今晚的工作时?只有在达到下一个稳定迭代时才进行?在任何错误修复之后?
  • 如果我想要更改菜单布局,我是否应该创建一个新分支,然后合并回主分支?
  • 我是否应该创建分支?对于只有我这一个开发者的情况,创建分支并将其合并回去与克隆存储库并将其拉回有什么区别?

对于一个版本控制新手,还有其他建议吗?


到目前为止,每个人都给了我很好的建议,但都非常团队导向。我想澄清一下:

目前,我只是在一些自己的网站上使用版本控制。并不是完全的自由职业工作,但对于版本控制而言,我是唯一接触网站代码的人。

此外,由于我在网站中使用PHP,因此不需要编译。

这是否会显著改变你的答案?

7个回答

25
大多数关于编程的问题,主要取决于你正在与谁一起工作。如果您是一个独立开发者,那么这不应该成为问题,因为您可以按自己的意愿进行操作。但是,如果您在一个团队中工作,需要共享代码,那么您应该与团队成员讨论“行为准则”,因为彼此之间分享更改有时可能会变得棘手。

关于行为准则的讨论不需要很长,可以非常简洁;只要每个人都知道如何使用程序员团队之间共享的存储库即可。如果您想使用Mercurial中的更高级功能(例如挑选或补丁队列),请尝试使用它们,以便不会对团队成员产生负面影响,例如在公共存储库上重新定位。

请记住,版本控制必须易于每个团队成员使用,否则它将无法使用。

何时/多久提交一次?在任何重大更改后,无论是否有效?我完成当天晚上吗?只有在达到下一个稳定迭代时才提交?在任何错误修复后?

在团队中工作时,有几种方法,但常见规则是尽早而又经常提交。你应该经常提交的主要原因是使合并冲突更容易处理。

合并冲突是指当至少两个人对同一行进行编辑时,合并已更改的文件时无法正常工作。如果您拥有一个包含多个文件中数行更改的非常大的更改提交,则接收者很难处理可能发生的冲突。如果保留这些更改过长时间,合并冲突会变得更加困难。

有一些例外规则需要经常提交,其中之一就是在出现重大更改时。虽然如果您有本地提交的能力(Mercurial 和 Git 本质上都支持),您可以提交重大更改,但只要修复了任何问题,应该在修复自己的重大更改后将其推送到共享存储库。

如果我想更改菜单布局,是否需要分支,然后再合并回来?

我应该创建分支吗?

有许多分支策略可供选择(1998 年发布的《流线型》论文提供了详尽的分支策略列表),当您为自己制定策略时,应该开放给自己选择。但是,在团队中工作时,最好与团队进行公开讨论,以确定是否需要创建分支。无论何时您都应该问自己以下问题:

  • 我的未来更改是否会破坏其他人的工作?

  • 我的团队是否会直接受到我所做的更改的负面影响,直到我完成为止?

  • 我的代码是可扔掉的吗?

如果以上任何一个问题的答案是肯定的,您应该可能公开分支,或者将其保留给自己(因为在Mercurial中有几种方法可以这样做)。您应该首先与团队讨论如何执行整个尝试,以查看是否有其他方法可以执行它,以及您是否要合并您的更改回来,有时存在一些因素,其中没有必要分支(这主要涉及代码的模块化程度)。

当您决定分支时,请准备好处理合并冲突。可以合理地假设创建分支并进行提交的人能够将其合并回“主分支”。在这些时候,如果团队中的每个人都做出相关的提交注释,那将是很棒的。

顺便说一句:您确实编写了良好的提交注释,对吧?没错吧!一个好的提交注释通常会告诉提交者制作该特定更改的原因或正在开发的功能,而不是一种模糊的“我进行了提交”的注释。这使得处理大型合并冲突的人更容易确定哪些行更改可以被覆盖,哪些行需要保留,同时查看修订历史记录。

编译时间,或者说构建时间,有时会影响到你讨论分支的决策。如果你的项目构建时间很慢,那么在你的分支中使用分阶段策略可能是个好主意。这种策略考虑到所有开发人员都应该集成到“主线”,并且经过批准的更改会被提升(或“晋升”)到下一个阶段,比如测试或发布线。这通常用类似于开源软件的标签名来说明:

main -o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-> ...
         \           \              \
test      o-----------o--------------o---------> ...
           1.0 RC1     \ 1.0 RC2      2.0 RC1
release                 o----------------------> ...
                          1.0

这样做的好处是测试人员可以在不被程序员打扰的情况下工作,并且对于那些处于发布管理中的人来说,有一个已知的基线。在分布式版本控制中,不同的线可能是克隆存储库,而且它看起来可能会有所不同,因为存储库共享版本控制图。然而,原则是相同的。
关于Web开发,几乎没有构建时间。但是,通过分阶段分支(或通过标记您的发布修订版本),如果您想检查难以跟踪的错误,则更容易回滚。
然而,另一件事情变得非常重要,那就是部署网站所需的时间。根据我的经验,版本控制工具在资产管理方面真的很差。处理总计多达数GB的艺术资产通常是Subversion(更多是Mercurial)难以处理的大问题。资产可能需要您以较少的时间成本进行处理,例如将它们放在共享空间中,在传统方式下进行同步和备份(艺术资产通常不像源代码文件那样同时进行工作)。
“对于我这个孤独的开发人员来说,分支和合并回来与克隆存储库并将其拉回有什么区别?”分支和保留远程存储库的概念现在比使用集中式版本控制工具更接近。您几乎可以认为它们是相同的东西。在Mercurial(以及git)中,您可以通过以下方式之一“分支”:克隆存储库或创建命名分支。
创建一个命名分支意味着你在所创建的存储库中为版本控制图形创建了一个新路径。创建一个克隆存储库意味着你将源存储库复制到一个新位置,并在克隆存储库的版本控制图形中创建了一个新路径。它们都是版本控制中一般概念下的不同实现。
实际上,你应该关心这两种方法之间唯一的区别在于用法。你可以克隆一个存储库以获得源代码的副本并有一个存储自己更改的地方,而当你想要进行小的实验时,你需要创建命名分支。
由于对于习惯于提交直线的人来说,浏览分支有点棘手,高级用户知道如何操作他们的版本,使版本历史记录与例如cherry pickingrebase保持“清洁”。目前,git文档实际上很好地解释了rebase

9

以下是我所遵循的实践:

  • 每次提交都要有意义:修复一个错误(或一组相关的错误),添加一个(小)新功能等。这个想法是,如果需要回滚,回滚会在明确定义的“边界”上进行。

  • 每个提交都应该有一个好的说明,解释你正在提交什么。养成这个习惯,你以后会感谢自己的。说明不必冗长,几句话就可以了。如果你正在使用缺陷跟踪系统,将一个缺陷号与你的提交关联起来也非常有帮助。

  • 现在我使用 git,分支非常快速和便宜,我倾向于为我即将实现的每个新功能创建一个新分支。我甚至从未考虑过在许多其他版本控制系统中这样做。所以分支取决于你使用的系统、你的代码库、你的团队等,没有硬性规定。

  • 我喜欢总是使用命令行并直接了解我的版本控制系统的命令。GUI 前端可能会引起断开,这可能是痛苦的,甚至是有害的。控制你的源代码非常重要,值得直接去做。但这仅仅是我的个人偏好。

  • 备份你的版本控制系统。我使用 Time Machine 备份我的本地存储库,然后将其推送到我的服务器上的远程存储库,并且该服务器也得到了备份。仅靠 VCS 不是真正的“备份”,它也可能像其他任何东西一样出现问题。


每次提交只解决一个错误或功能,这样可以节省追踪时间,也让团队其他成员更容易了解您如何解决问题。 - Peter Bernier

2

我会在完成工作并且代码可以正常运行时提交。将代码提交到其他人使用的地方是不好的习惯。

分支是一件人们会争论的事情。有些人说永远不要分支,只需使用开关来使某些功能起作用或者不起作用。你可以根据自己的感觉来做,但不要仅仅因为你可以就分支。当我处理重要的工作时,我会使用分支,以免意外提交损坏的代码影响到别人。


2
什么时候/多久提交代码更好呢?
可能会得到很多矛盾的答案。我的观点是,当修改完成并且可以正常工作时,应该提交更改,并且每次提交(或检入)应该只包含一个“编辑”。 “编辑”是一组原子性更改,它们在一起修复缺陷或实现新功能。
有一种理论是,即使代码不起作用,也应该每几个小时检查一次,但在这种情况下,您需要在自己的分支上工作-您不希望将错误代码检入主线或共享分支。
每天晚上检入代码的好处在于备份(假设您的存储库在另一台机器上)。
至于分支:
- 您应该有一个包含始终有效代码的主线。 - 您应该有一个包含最新代码的当前开发分支。当您满意它(并通过了所有测试)后,您应该将其合并回到主线中。 - 您可能需要一个包含最后发布版本的分支。这可用于测试/调试错误并发布补丁(在极端情况下)。

2
  • 在每次提交之前更新
  • 提供提交注释
  • 一旦完成某个任务就立即提交代码
  • 不要提交任何导致代码库无法编译或有错误的代码
  • 每天早上更新
  • 如果有重要的更新,请与同事进行口头沟通
  • 仅提交与一个特定任务相关的代码(例如修复错误,实现功能)
  • 不必担心提交非常小的更改,只要符合前面的规则即可

顺便问一下,Subversion有哪些不好的经历吗?


糟糕的经历?在将目录上移一级时,它出了问题并停在了半路,删除了一个包含大部分网站内容的文件夹,并以某种方式为该移动生成了十几个版本。我花了大部分时间试图撤销并恢复数据。 - Austin Hyde
也许你使用的是不好的客户端?Subversion本身有一些缺点,在工作了一段时间后就可以观察到。 - Bozho
在Subversion中移动目录是一个两步过程。您必须删除旧文件并添加新文件。有时这不起作用,其中一种情况是如果几个开发人员正在处理即将移动的文件,但忘记提交更改。然后他们的更改将被神奇地删除。这对于经常重构其代码的敏捷实践者来说是一个大问题,例如有时需要移动其代码文件。 - Spoike
2
我一直在重构很多代码,很少遇到问题。 - Bozho
当我试图将C#中的类移动到新的命名空间时,我遇到了Subversion的问题;AnkhSVN破坏了SVN存储库。所谓的破坏是指无法检索或以任何方式修复存储库中的最新版本,但旧版本仍然可以工作,我们无法提交任何新内容到存储库。这是几年前的事情了,AnkhSVN和后来的SVN版本可能已经解决了这个问题,但那时候它损害了我对SVN作为版本控制的信心。 - Spoike

1

问:我应该在什么时候/多久提交?在任何重大更改后,无论是否有效?当我完成今晚的工作时?只有在达到下一个稳定迭代时?在任何错误修复后?

答:每当您感到舒适时,我会在完成并且可用的工作单元之后立即提交(这并不意味着完整的任务必须完成)。但是,如果代码无法编译,您不应该提交它(可能会影响团队中的其他人)。此外,如果有任何可能需要在完成之前实施快速修复或小更改,则不应将不完整的内容提交到主干。

问:如果我想要更改菜单的布局,我会分支吗,然后再合并回来?

答:只有在有可能需要在完成任务之前实施快速修复或小更改时才需要分支。

分支的好处是,您在分支中进行的所有提交仍将可供将来参考(如果需要)。而且,我认为它比克隆存储库要简单和快速;-)


1

我同意在提交时间方面与其他人的看法。

关于分支,我通常只在开发中遇到打破他人工作或需要将补丁滚动到已经有更改但不应该进入生产的文件时才进行分支。如果你是唯一的开发者,则第一种情况并不适用。

我使用标签来管理发布 - “生产”标签始终与当前生产代码相关联,并且每个发布都带有“release-YYYYMMDD”标签。这允许您在必要时进行回滚。


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