摘要
介绍 Git 的主要分支、功能分支、发布分支和热修复分支,以及它们的协作与合并流程。
关键词
Git、版本控制、分支管理、发布流程
为什么使用 Git?
讨论 Git 与集中式版本控制系统的优缺点,可以从开发者的实际体验出发。对我来说,Git 是当下最喜欢的版本控制工具,它改变了开发者看待分支与合并的方式。在过去使用 CVS、Subversion 时,分支和合并往往让人担心,也只是偶尔才会进行的操作。
Git 让分支与合并变得简单而日常,不再令人畏惧。版本控制工具本就应该帮助开发者方便地管理这些操作。
分布式协作与中心仓库
这种分支模型采用一个约定上的中心“事实”仓库。由于 Git 是分布式版本控制系统,技术上并不存在真正的中心仓库;这里只是在协作中赋予它中心地位。我们沿用 Git 用户熟悉的名字,将其称为 origin。

每位开发者都从 origin 拉取并向其推送修改。除了这种集中式同步关系,开发者也可以彼此拉取变更,组成小组协作。
例如,两位或多位开发者共同开发大型新功能时,可以先在小组内协作,避免过早把未完成的工作推到 origin。上图展示了 Alice 与 Bob、Alice 与 David,以及 Clair 与 David 的协作关系。
从技术上说,这只是 Alice 添加了名为 bob、指向 Bob 仓库的 Git 远程地址,Bob 也进行了对应设置。
两条主要分支

该开发模型借鉴了既有实践。中心仓库包含两条长期存在的主要分支:
masterdevelop
Git 用户通常都熟悉 origin 上的 master 分支。与它并行的另一条长期分支是 develop。
origin/master 的 HEAD 应始终保持可用于生产发布的状态。
origin/develop 的 HEAD 包含为下一次发布准备的最新开发变更,因此也称“集成分支”。自动化的每夜构建通常从这里产生。
当 develop 的代码稳定且准备发布时,应将变更合并回 master,并打上版本标签。具体操作将在后文说明。
按照这一约定,每次合并到 master 都意味着一次新的生产发布。如果严格遵守,就可以通过 Git hook 在 master 出现新提交时自动构建并部署到生产服务器。
辅助分支
除了 master 和 develop,模型还使用辅助分支,支持团队并行开发、功能追踪、发布准备以及线上紧急修复。这些分支都有有限的生命周期,完成使命后会被删除。
辅助分支包括:
- 功能分支。
- 发布分支。
- 热修复分支。
每类分支都有明确用途,并严格约定从哪里创建、最终合并到哪里。
这些分支在技术上并无特殊之处,仍是普通 Git 分支,区别仅在于使用方式。
功能分支

可以从以下分支创建:
develop
必须合并回:
develop
命名规则:除 master、develop、release-* 和 hotfix-* 之外的名称。
功能分支有时也称主题分支,用于开发近期或未来版本中的新功能。开始开发时,未必已经确定它属于哪次发布。功能开发期间保留该分支,完成后合并到 develop,纳入后续版本;如果实验结果不理想,也可以将其丢弃。
功能分支通常只存在于开发者自己的仓库中,不放在 origin。
开始开发新功能时,从 develop 创建分支:
| |
完成的功能可以合并进 develop,纳入下一次发布:
| |
--no-ff 参数使合并始终创建新的合并提交,即使本可进行快进合并。这样能够保留功能分支曾经存在的历史,并将实现该功能的提交归为一组。对比如下:

如果不保留合并提交,就很难从 Git 历史直接看出哪些提交共同实现了一个功能,需要逐条阅读日志。此时回滚整个功能会较为麻烦;使用 --no-ff 则容易得多。
这种做法会增加少量合并提交,但其收益明显大于成本。
发布分支
可以从以下分支创建:
develop
必须合并回:
develop和master
命名规则:
release-*
发布分支用于为新的生产版本做最后准备,包括收尾、小范围缺陷修复,以及版本号、构建日期等元数据更新。这些工作独立在发布分支完成后,develop 就可以继续接收下一个大版本的功能。
当 develop 已经基本达到本次发布目标时,就适合创建发布分支。至少,本次计划发布的全部功能应已合并进 develop。
版本号在创建发布分支时才正式确定。在此之前,develop 代表的是“下一个版本”的变化,但这个版本最终叫 0.3 还是 1.0,要到创建发布分支时才明确。
发布分支从 develop 创建。例如,当前线上版本为 1.1.5,develop 已经准备好下一次较大的发布,并决定版本号为 1.2,就创建对应名称的分支:
| |
创建并切换分支后,更新版本号。这里的 bump-version.sh 是一个示例脚本,用来修改工作副本中的文件,反映新的版本号。也可以手工修改,关键是将版本号变更提交。
发布分支可以保留一段时间,直到正式上线。这期间在该分支修复缺陷,而不是在 develop 上进行。严禁在这里加入大型新功能;新功能应进入 develop,等待下一个大版本。
发布分支准备就绪后,先将其合并进 master,因为按约定 master 的每次提交都对应发布;再为 master 上的提交打标签,方便以后查找该历史版本;最后将发布分支的变更合并回 develop,确保后续版本也包含这些修复。
前两步的 Git 操作:
| |
此时发布已完成,并已添加版本标签。
补充:可以使用
-s或-u <key>参数对标签进行加密签名。
为保留发布分支的修改,还需要将其合并回 develop:
| |
这一步可能出现合并冲突,尤其是已经修改了版本号时。如有冲突,应解决后提交。
至此发布流程完成,不再需要的发布分支可以删除:
| |
热修复分支

可以从以下分支创建:
master
必须合并回:
develop和master
命名规则:
hotfix-*
热修复分支与发布分支相似,也用于准备生产发布,但这种发布并非事先计划。当线上版本出现必须立即修复的严重问题时,可以从 master 上对应生产版本的标签创建热修复分支。
它的关键作用是:一位成员准备紧急修复时,其他成员仍可在 develop 上继续正常开发。
热修复分支从 master 创建。例如,线上运行的 1.2 版本出现严重缺陷,而 develop 的改动尚不稳定,就可以这样创建分支并修复:
| |
创建分支后,不要忘记更新版本号。
然后修复问题,通过一个或多个独立提交保存修改。
| |
修复完成后,既要合并回 master,也要合并回 develop,确保下一次发布同样包含该修复。这与完成发布分支的流程基本一致。
首先更新 master,并为新版本打标签:
| |
补充:可以使用
-s或-u <key>参数对标签进行加密签名。
接着将修复合并进 develop:
| |
这里有一个例外:如果当前已经存在发布分支,应将热修复合并到该发布分支,而不是直接合并到 develop。
当发布分支完成并合并回 develop 时,修复也会一并进入 develop。如果 develop 的工作立即需要这项修复、无法等待发布分支结束,也可以提前将修复安全地合并到 develop。
最后删除临时热修复分支:
| |
总结
这种分支模型并没有惊人的新概念,但文章开头的全景图在项目中非常有用。它提供了清晰、易理解的模型,让团队成员对分支与发布流程形成共同认识。
这里提供该图的高清 PDF:gitflow-model.pdf。可以打印出来放在手边,随时参考。
