Appearance
决断代码取舍
现在特性分支上已合并好了贡献者的代码,是时候决断取舍了。本节将回顾一些之前学过的命令,以看清将要合并到主干的是哪些代码,从而理解它们到底做了些什么,是否真的要并入。
一般我们会先看下,特性分支上都有哪些新增的提交。比如在 contrib 特性分支上打了两个补丁,仅查看这两个补丁的提交信息,可以用--not 选项指定要屏蔽的分支 master,这样就会剔除重复的提交历史:
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon
Date: Fri Oct 24 09:53:59 2008 -0700
seeing if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon
Date: Mon Oct 22 19:38:36 2008 -0700
updated the gemspec to hopefully work better
还可以查看每次提交的具体修改。请牢记,在 git log 后加 -p 选项将展示每次提交的内容差异。 如果想看当前分支同其他分支合并时的完整内容差异,有个小窍门:
$ git diff master
虽然能得到差异内容,但请记住,结果有可能和我们的预期不同。一旦主干 master 在特性分支创建之后有所修改,那么通过 diff 命令来比较的,是最新主干上的提交快照。显然,这不是我们所要的。比方在 master 分支中某个文件里添了一行,然后运行上面的命令,简单的比较最新快照所得到的结论只能是,特性分支中删除了这一行。
这个很好理解:如果 master 是特性分支的直接祖先,不会产生任何问题;如果它们的提交历史在不同的分叉上,那么产生的内容差异,看起来就像是增加了特性分支上的新代码,同时删除了master 分支上的新代码。
实际上我们真正想要看的,是新加入到特性分支的代码,也就是合并时会并入主干的代码。所以,准确地讲,我们应该比较特性分支和它同 master 分支的共同祖先之间的差异。
我们可以手工定位它们的共同祖先,然后与之比较:
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
但这么做很麻烦,所以 Git 提供了便捷的 ... 语法。对于 diff 命令,可以把 ... 加在原始分支(拥有共同祖先)和当前分支之间:
$ git diff master...contrib
现在看到的,就是实际将要引入的新代码。这是一个非常有用的命令,应该牢记。
1.代码集成
一旦特性分支准备停当,接下来的问题就是如何集成到更靠近主线的分支中。此外还要考虑维护项目的总体步骤是什么。虽然有很多选择,不过我们这里只介绍其中一部分。
8.2合并流程
一般最简单的情形,是在 master 分支中维护稳定代码,然后在特性分支上开发新功能,或是审核测试别人贡献的代码,接着将它并入主干,最后删除这个特性分支,如此反复。来看示例,假设当前代码库中有两个分支,分别为ruby_client 和php_client,如图下图:多个特性分支 所示。然后先把 ruby_client 合并进主干,再合并php_client,最后的提交历史如下图:合并特性分支之后 所示。
这是最简单的流程,所以在处理大一些的项目时可能会有问题。
对于大型项目,至少需要维护两个长期分支 master 和 develop。新代码(下图:特性分支合并前 中的 ruby_client)将首先并入 develop分支(下图:特性分支合并后 中的 C8),经过一个阶段,确认develop 中的代码已稳定到可发行时,再将 master 分支快进到稳定点(下图:特性分支发布后 中的 C8)。而平时这两个分支都会被推送到公开的代码库。
这样,在人们克隆仓库时就有两种选择:既可检出最新稳定版本,确保正常使用;也能检出开发版本,试用最前沿的新特性。你也可以扩展这个概念,先将所有新代码合并到临时特性分支,等到该分支稳定下来并通过测试后,再并入develop 分支。然后,让时间检验一切,如果这些代码确实可以正常工作相当长一段时间,那就有理由相信它已经足够稳定,可以放心并入主干分支发布。