翻译:《一个成功的Git分支模型》为什么是有害的
原文链接:https://barro.github.io/2016/02/a-succesful-git-branching-model-considered-harmful/
当大家开始使用Git并且开始了解到分支概念及分支方便之处的时候,你们可能会在Google上搜一搜相关知识,然后经常会搜到一篇注明的博客A success Git branching model。最大的问题是这篇文章出现在所有搜索结果的最前面,原本他应该用做一个使用分支开发的反例。
《一个成功的分支模型》错在了哪
直入正题,这种开发方式里你会把一切都共享到远程分支,然后merge到本地,本来很简单的事情变得很麻烦了。开发可靠系统的原则是保持理智。这个分支模型错在一开始就没有使用众所周知的master分支作为工作分支。
用独立的分支来开发功能很难确保合并的时候各项功能正常。这个问题在持续集成概念被广泛认可的今天尤其严重。只有通过周期性得把所有的变动集成在一起,你才才可以避免了大的集成问题,这些集成问题都会都会花费你大量的时间去解决,尤其是几百个上千个人开发的大项目。这个分支模型体现的开发实践鼓励程序员在各自分支上开发功能,这将导致巨大的集成问题而不是避免他。
除此之外,在《一个成功的分支模型里》里,合并提交记录被鼓励作为集成代码变动的主要方式。我将会解释为什么合并提交是不好的以及用了这种方法,你将失去的东西。
合并提交错在了哪
《一个成功的分支模型》讲了非向前合并提交可以被认为是一种保持某个功能相关的commit记录的方式。然后如果你决定这个功能不合适,你可以revert那个提交然后整个功能都去掉了。我认为这是一个去掉一个功能或者在第一次开发就完成这个功能是非常罕见的场景。
在Git中,合并经常会造成额外的一些提交记录,这些记录有一些特殊的日志信息像“Merge branch ‘some-branch’ of git://git.some.domain/repository/”。这个东西不能提供任何关于代码变动的信息。你不得不去读commit信息,可能要读到第二段,这还不包括得看分支历史。
有一个非线性的历史,问题只有在集成的时候才包括,也是得git bisect更难了,你可能两个独立分支都非常好,但是合并提交失败了,因为你们的改变没有冲突。这种情况下尤其严重,你如一个开发者改了接口,然后其他的开发者用了旧的接口定义。这种问题很难被定位和解决,但是有了线性的历史,没有任何合并提交记录,我们可以很快发现哪次提交造成了问题。
更简单的解决方案
让我展示一个更简单的替代方案,我们可以称他为仙人掌模型。这个名字来源于在这个方案中,所有的分支都是从master分支切出来的并且从不合并回去。仙人掌模型反映了一个用git开发更自然的方法,确保持续集成法则可用。
在上图中,你可以看到仙人掌分支模型遵守下面章节会讲到的准则。一些准则可能可能需要 Gerrit 和一些类似的集成代码审查工具
所有的开发都在master分支
master分支是你克隆项目后的默认分支,既然这样我们为什么不把所有的开发放在这个分支呢?不再需要猜也没必要给开发的分支写文档。这个是唯一从中央仓库克隆的项目并且对每个人都是最新的分支。个人开发者鼓励使用本地分支,避免分享到远端分支。
开发者应该周期性git rebase 他们的变动,保持和最新的origin/master同步。这确保我们不会在一个过期的基准线上开发。
用本地分支
仙人掌模型不是不鼓励使用分支,因为分支是有用的。特别是一个独立开发者应该在本地仓库使用临时的功能分支,然后在合适的时机把它们集成到origin/master,从而分享给大家。本地的分支主要是为了测试和代码审查的时候,在功能之间切换更简单。
图二、图三通过一个可视化的树形结构展示了一个本地分支和rebase的一个基本的准则。在图二中,我们的情况是有两个活跃的本地开发分支(紫色圆圈)和一个准备代码审查并集成到origin/master(黄色圆圈)的分支(蓝色圆圈)。在图三中,我们用两次提交更新了orogin/master(黄蓝圆圈),然后提交了两次准备代码审查和集成的commit信息(蓝色)。由于分支不会自动消失,所以集成后的提交记录仍然在本地保存(灰色圆圈)。
分享远程分支
主要原则:应该避免共享远程分支。所有的改动应该都体现在origin/master上,其他的开发者应该通过持续的更新,把它们的改动基于最新的origin/master。这确保了我们不会碰到很多功能分支合并时的集成地狱。
如果你使用代码审查工具,像Gerrit或者github,然后你可以只是git fetch提交链然后在最新的commit上开发。然后把你的代码变动提交到你自己仓库特定分支里,这样你就和origin/master保持同步了
发布分支从orgin/master分支切出来
发布分支从master分支切出来。如果我们需要热修复,在发布分支上做,然后把使用的bug修复合并到master分支。通过一些特定的tag和分支名字,我们可以做到自动发布。
只有向前合并
git merge从不会被使用。要合并到orign/master的变动通过git rebase和git cherry-pick来实现。这避免了因为merge而弄乱了仓库,也避免了 圣诞树外表 。Rebase同样会让提交历史呈线性,这样git bisect就非常容易使用了。
如果你使用Gerrit,你同样可以采用选择性提交策略。这可以非常方便得按照意愿顺序把一些列的提交合并到origin/master,而不是非要按照代码审查的顺序来。
结论
对版本控制,git是一个非常棒的工具。有了它,你可以完成很多难以办到的事情。分支其实是指向 特定提交记录的指针 ,你可以非常方便得创建分支。同样,你可以做合并,这让分支用起来更简单。但是这些工具应该让分支对开发者来说更简单而不是更复杂。
我见过数以百计的开发者使用着非常糟糕的开发实践。有些组织甚至想从中央仓库移除master分支,这是不理智的。