分支合并是Git中常见的操作,在默认情况下,Git采用fast-forward的方式进行分支合并。那么不使用fast-forward方式有什么不同呢?
假设我们在当前master分支下创建一个speedup分支,并在speedup分支做了一些事情(三次commit,如图中的白色圆圈)之后,准备把它push到远程库。同时,在master分支没有什么变化,依然保持我们新建分支之前的状态。如图所示:
一旦项目维护者通知我的分支可以被整合了,她可能会使用常规的git fetch
和git merge
操作。这样,我的工作被添加到了资源树(source tree)上。master作为speedup分支的base branch,自从上一次提交(图中灰色圆圈)之后就没有改变。Git将执行fast-forward合并方式。分支历史是线性的,像下图所示的(左图):
另一种不同的合并方式是使用 -no-ff
参数(意思是no fast-forward)。在这种情况下,分支历史会有稍许区别(右图):多了一个commit(虚线的圆圈)来实现合并。这个commit还会用右边的信息提示我们这次分支合并。
Git默认使用fast-forward方式。这可以被调整,我们可以通过修改配置信息更改为非fast-forward模式(设置非fast-forward为默认)。
非fast-forward方式的一种典型场景是Github上的绿色合并按钮,这是其pull request workflow的一部分。当某人创建了一个Pull请求,点击项目页面上的这个按钮可以完成修改信息的合并操作(每当github认为可以这么做的时候)。
不幸的是,至少到目前为止,github的Web接口对合并的操作好像你添加了-no-ff
参数。也就是说,即使可以使用fast-forwarding,github也不会这么做。一个可能的原因是这个pull请求可以被识别。例如,几个最近的提交(commit)就像这样:
看这个表,很明显这些修改都可以用fast-forward模式。哎,github的合并方式把本来是线性的分支弄成了像铁路一样的图。
简而言之,非fast-forward合并坚持“明确的分支(explicit branches)理念。它可能使分支历史变得复杂、非线性化,以此保留分支的信息(在Github上是pull请求)。另一方面,fast-forward合并方式使得所有的修改历史成线性表示,方便其他工具的使用(log,blame,bisect)。每一条分支的信息并不明白表示,然而这并不是一个大问题,如果项目在commit信息和问题追踪(issue tracker)上制定了严格的交叉引用。
哪一种方式你觉得更好,fast-forwarding或者非fast-forwarding?
相关文章:
Extracting Parts of Git Repository and Keeping the History
Cross-Reference: Commit Message and Issue Tracker
Git Viewer: GitHub vs Google Code
Git pre-commit hook and smoke testing