原文作者:Martin Fowler

原文地址

现代源码控制系统提供了强有力的工具,使得在源码中创建分支变得容易。但最终这些分支都不得不合并到一块儿,许多团队还花了大量的时间把这些分支杂乱的盘根错节粘合在一起。有几个模式可以让团队有效地使用分支,并让团队专注在集成多个开发者的工作和组织通往生产(production)发布的路径周围。贯穿整体的主题是,分支应该被频繁地集成,并且努力都应该集中在可以以最小代价发布到生产环境的健康主线上。



源代码对于任何软件开发团队来说都是至关重要的资产,在过去几十年的时间里,大量的源码管理软件被开发出来来让代码保持规整。这些工具让变更可被追踪,让我们可以重建先前版本的软件,并且可以看见它是怎么随着时间发展的。这些工具也是拥有多个程序员团队的坐标中心,所有人都在一个共同的代码库上工作。通过记录每个开发者所作的变更,这些系统可以一次性跟踪多条工作线,并帮助开发者想出如何将这些多条工作线合并到一起。

这种工作线的分裂与合并是软件开发团队的核心工作流,并且一些模式已经进化出一种方法来帮助我们处理这些活动。就像大多数软件模式一样,它们都不是团队必须遵守的黄金法则。软件开发的工作流非常依赖于所处的环境(context),特别是团队的社会结构和团队遵循的其它实践。

在这篇文章中,我的任务是讨论这些模式,并且是在单篇文章的上下文中这样做的。在这篇文章中我描述了模式,但在模式的解释中穿插了叙述性的部分,这些叙述性的部分可以更好的解释环境和模式之间的相互关系。为了更轻易的区分它们,我使用“✣”符号标记了模式的部分。

基本模式

在思考这些模式时,我发现发展两个主要类别是很有用的。一组着眼于集成,即多个开发者如何将他们的工作结合成一个连贯的整体。另一组则着眼于通往生产的路径,使用分支来帮助管理从集成的代码库到在生产中运行的产品的路径。一些模式对它们两者都进行了支撑,我会把这类视为基础模式。剩下的一些模式既不是基本模式,也不能归于这两个主要组别之中——所以我将把它们留到最后。

源码分支行为 ✣

创建一个副本并记录该副本的所有变更。

如果几个人在同一个代码库中工作,那么在相同的文件上进行工作将很快变得不可能。如果我想运行编译,而我的同事正在输入表达式,那么编译就会失败。我们将不得不对彼此吼叫:“我正在编译,别改东西”。即使只有两个人,这也很难持续,更别说一个更大的团队了。

这个问题的简单答案是,每个开发者都持有一份代码库的副本。现在我们可以很容易地工作在自己的功能上了,但一个新的问题出现了:当我们完成工作后,如何将我们的两个副本再合并到一起?

源码控制系统使这一过程更加容易。关键在于,它将每个分支的每一个改动都记录为提交(commit)。这不仅可以确保没有人忘记他们对utils.java所做的小改动,而且记录改动可以使合并更容易进行,特别是当几个人修改了同一个文件时。

这将我引向本文要用到的分支的定义。我把一个分支定义为代码库中的一个特定的提交序列。分支的头部,或者说顶端,是该序列中的最新提交。

1. 一个分支是一系列的提交
2. 头部(或顶端)是这一系列的最新提交

  1. 一个分支是一系列的提交
  2. 头部(或顶端)是这一系列的最新提交

这是名词,但也有动词,“进行分支(to branch)”。这时我指的是创建一个新的分支,也可以看成是把原来的分支拆分成两个。当一个分支的提交被应用到另一个分支时,分支会合并。

1. 当有两个提交被平行的创造时,一个分支将会分开
2. 一个分支可以被合并到另一个分支。将会有一些工作来处理这些平行的变更
3. 如果自上次合并都没有变更,在一个分支上的一个变更可以简单地被应用到另一个上去

  1. 当有两个提交被平行的创造时,一个分支将会分开
  2. 一个分支可以被合并到另一个分支。将会有一些工作来处理这些平行的变更
  3. 如果自上次合并都没有变更,在一个分支上的一个变更可以简单地被应用到另一个上去