当特性分支中所有的工作都已经准备好整合进入更靠近主线的分支时,接下来的问题就是如 何进行整合了。 此外,还有一个问题是,你想使用怎样的总体工作流来维护你的项目? 你的 选择有很多,我们会介绍其中的一部分。
合并工作流
一种非常简单的工作流会直接将工作合并进入 master 分支。 在这种情况下, master 分支 包含的代码是基本稳定的。 当你完成某个特性分支的工作,或审核通过了其他人所贡献的工 作时,你会将其合并进入 master 分支,之后将特性分支删除,如此反复。 如果我们的版本库 包含类似
包含若干特性分支的提交历史。
的两个名称分别为 ruby_client 和 php_client 的 分支,并且我们先合并 ruby_client 分支,之后合并 php_client 分支,那么提交历史最后 会变成合并特性分支之后。
的样子。Figure 1. 包含若干特性分支的提交历史。
维护项目
Figure 2. 合并特性分支之后。
这也许是最简单的工作流了,但是当项目更大,或更稳定,你对自己所引入的工作更加在意 时,它可能会带来问题。
如果你的项目非常重要,你可能会使用两阶段合并循环。 在这种情况下,你会维护两个长期 分支,分别是 master 和 develop , master 分支只会在一个非常稳定的版本发布时才会更 新,而所有的新代码会首先整合进入 develop 分支。 你定期将这两个分支推送到公共版本库 中。 每次需要合并新的特性分支时(
合并特性分支前。
),你都应该合并进入 develop 分支(合并特性分支后。);当打标签发布的时候,你会将 master 分支快进到已经稳定的
develop 分支(一次发布之后。)。
Figure 3. 合并特性分支前。
Figure 4. 合并特性分支后。
维护项目
Figure 5. 一次发布之后。
这样当人们克隆你项目的版本库后,既可以检出 master 分支以构建最新的稳定版本并保持更 新,也可以检出包含更多新东西的 develop 分支。 你也可以扩展这个概念,维护一个将所有 工作合并到一起的整合分支。 当该分支的代码稳定并通过测试之后,将其合并进入 develop 分支;经过一段时间,确认其稳定之后,将其以快进的形式并入 master 分支。
大项目合并工作流
Git 项目包含四个长期分支: master 、 next ,用于新工作的 pu (proposed updates)和用 于维护性向后移植工作(maintenance backports)的 maint 分支。 贡献者的新工作会以类 似之前所介绍的方式收入特性分支中(见
管理复杂的一系列接收贡献的平行特性分支。)。
之后对特性分支进行测试评估,检查其是否已经能够合并,或者仍需要更多工作。 安全的特 性分支会被合并入 next 分支,之后该分支会被推送使得所有人都可以尝试整合到一起的特 性。
维护项目
如果特性分支需要更多工作,它则会被并入 pu 分支。 当它们完全稳定之后,会被再次并入
master 分支。 这意味着 master 分支始终在进行快进, next 分支偶尔会被变基,而 pu
分支的变基比较频繁:
Figure 7. 将贡献的特性分支并入长期整合分支。
当特性分支最终被并入 master 分支后,便会被从版本库中删除掉。 Git 项目还有一个从上 一次发布中派生出来的 maint 分支来提供向后移植过来的补丁以供发布维护更新。 因此,
当你克隆 Git 的版本库之后,就会有四个可分别评估该项目开发的不同阶段的可检出的分支,
检出哪个分支,取决于你需要多新的版本,或者你想要如何进行贡献;对于维护者来说,这 套结构化的工作流能帮助它们审查新的贡献。
变基与拣选工作流
为了保持线性的提交历史,有些维护者更喜欢在 master 分支上对贡献过来的工作进行变基和 拣选,而不是直接将其合并。 当你完成了某个特性分支中的工作,并且决定要将其整合的时 候,你可以在该分支中运行变基命令,在当前 master 分支(或者是 develop 等分支)的基 础上重新构造修改。 如果结果理想的话,你可以快进 master 分支,最后得到一个线性的项 目提交历史。
另一种将引入的工作转移到其他分支的方法是拣选。 Git 中的拣选类似于对特定的某次提交的 变基。 它会提取该提交的补丁,之后尝试将其重新应用到当前分支上。 这种方式在你只想引 入特性分支中的某个提交,或者特性分支中只有一个提交,而你不想运行变基时很有用。 举 个例子,假设你的项目提交历史类似:
维护项目
Figure 8. 拣选之前的示例历史。
如果你希望将提交 e43a6 拉取到 master 分支,你可以运行:
$ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
这样会拉取和 e43a6 相同的更改,但是因为应用的日期不同,你会得到一个新的提交 SHA-1 值。 现在你的历史会变成这样:
维护项目
如果你在进行大量的合并或变基,或维护一个长期的特性分支,Git 提供的一个叫做“rerere”的 功能会有一些帮助。
Rerere 是“重用已记录的冲突解决方案(reuse recorded resolution)”的意思——它是一种简 化冲突解决的方法。 当启用 rerere 时,Git 将会维护一些成功合并之前和之后的镜像,当 Git 发现之前已经修复过类似的冲突时,便会使用之前的修复方案,而不需要你的干预。
这个功能包含两个部分:一个配置选项和一个命令。 其中的配置选项是 rerere.enabled ,把 它放在全局配置中就可以了:
$ git config --global rerere.enabled true
现在每当你进行一次需要解决冲突的合并时,解决方案都会被记录在缓存中,以备之后使 用。
如果你需要和 rerere 的缓存交互,你可以使用 git rerere 命令。 当单独调用它时,Git 会 检查解决方案数据库,尝试寻找一个和当前任一冲突相关的匹配项并解决冲突(尽管当
rerere.enabled 被设置为 true 时会自动进行)。 它也有若干子命令,可用来查看记录
项,删除特定解决方案和清除缓存全部内容等。 我们将在 Rerere 中详细探讨。