SVN时代的源码管理不过是将源码存放在特定的服务器上,并且记录每一次的修改,,同时配合工具可以在历史版本之间切换。现代软件工程对于源码管理的定位不仅仅是对历史的跟踪,而是将其融入到工程体系中作为完整工作流的 一部分。基于Git的源码管理规范具象表现为分支管理,它已经超越了“存储历史版本”这一狭义范畴,融合了协作、集成、部署和交付,在持续集成和持续交付体系中甚至可以说源码管理规范是所有流程得以实施的基石。 分支策略并不是硬性的、一成不变的,团队的鬼马、组织结构的原因都可能影响具体细则。目前主流的三种分支策略分别为GitHub Flow、GitLab Flow和Git Flow,每种策略都有其适用的场景,没有绝对的优劣之分。下面将简单描述三种策略模型以及各自的优缺点。
Git Flow
Git Flow被普遍认为是有Vincent Driessen在2010年提出的一种分支管理策略,其流程围绕两个平行分支进行:
- master分支值记录已交付生产环境的代码,只接受merge不接受push,而且只接受release分支和hotfix分支的merge请求。换句话说,master分支的每条merge提交记录均对应已上线的某个版本。
- develop分支的定位在开发阶段接受由不同团队成员负责的所有feature分支的merge请求,所以有人将其称之为“集成分支”。develop分支可以在最新的master、hotfix或release分支的基础上分化而来,并且只能被merge到release分支。
在master和develop两个核心分支基础上,Git Flow进一步演化出一下角色分支:
-
feature分支是针对单个业务功能的分支,从develop分支基础上分化而来并且只能被merge到develop分支。feature分支是开发者编码的主战场。另外,feature分支通常只存在于其对应负责人的本机环境,开发完成后负责人merge的develop分支,然后将develop分支推送到远端。
-
release分支有些难理解,稍有不慎就会与develop混淆。通俗的讲,develop分支始终是“面向未来的”,而release分支是“面向最近一次交付的”。例如,master分支的最新记录对应线上产品的1.0版本,现在有一批需求预期在两个月后的1.1版本中开发。开发者从master分支基础上分化出develop分支,进而细化出多个feature分支进行开发。但是在开发进行到一个月的时候,领导层决定对产品的发布策略进行调整,将目前已完成的部分功能集成为一个小版本1.0.1,。这种情况下的解决方案是将这些功能对应的feature分支全部merge到develop分支,然后在develop基础上分化出release-1.0.1,最后交付上线后将release-1.0.1分支merge到master分支。如果release-1.0.1分支包含了现阶段所有的feature分支,即与develop分支完全同步,也可以将其merge到develop分支,这是一种相对极端的情况。
-
hotfix分支用来因对突发的情况,典型的场景是修复线上的紧急bug。hotfix分支有最新的master分化而来,只能被merge的master或者develop分支。
综上所述,Git Flow可以概括为如下图的开成模型,其中master、develop和feature是Git Flow的常驻分支,release和hotfix用于应对一些计划之外的情况。

Git Flow的优点是,各分支角色的定位非常精细和明确,集成命名规范约束可以领源码的分支结构一目了然。并且Git Flow是历史相对悠久(GitHub Flow与2011年被提出,Gitlab Flow与2014年被提出)的一种分支策略,其工具生态相对完善。但从Git Flow的流程模型中可以看出,它针对的仍然是比较传统的项目迭代模式,即比较注重版本的界限。将其应用到意在弱化甚至消除版本概念的敏捷开发和持续交付模式中则显得异常繁琐。Git Flow较适合体量较大、更新频率低、品控苛刻的ToB类产品。
GitHub Flow
与Git Flow的繁琐相比,Scott Chacon提出的GitHub Flow是另一种极端,形式上非常简单,但是在某些环节强依赖与人工介入。GitHub Flow只有两个分支:master和feature,开发者从master分支基础上直接分化出一个或多个feature分支。Git Flow不同的是,GitHub Flow的feature分支不允许由开发者本人merge到master分支。而是需要推送到远程服务器泛起Pull Request,然后又专门负责代码审查(review)的人在确定代码的正确性之后再合并到master分支。也就是说,除了Git本身的分支规范以外,GitHub Flow还需要额外人工介入的中间流程,其参与者分为两种角色:feature分支的开发者和负责review和merge的审查员,缺一不可,流程模型如下:

GitHub Flow核心理念是master分支任何一次merge行为后的代码都是可交付的,弱化了版本的概念。这种策略最大的优势是利于持续集成,监听服务只需订阅master分支的merge行为即可。但是缺陷同样明显,GitHub Flow其实是一种偏理想化的策略,但实际工作中强制依赖人工审查的模式会造成master分支的安全性与审查员的个人水平直接挂钩,能够把好这一关并不是一件容易的事情。
Gitlab Flow
假设产品团队具备完善的持续集成和继续交付体系,GitHub Flow是比Git Flow更好的选择,但是安全问题仍是一块难以绕过的绊脚石。GitHub Flow的症结一方面是无法保证合并到master分支的代码绝对安全;另一方面是master分支一旦有merge行为变回触发集成和交付直接被同步到生产环境,换句话说,master分支与生产环境之间没有任何过渡。这对第二点Gitlab Flow的优化方案是master分支与生产环境之间设立一旦屏障:预生产环境(per-production,简称per-prod)。
从生产环境的对应角度上,master分支在Git Flow和GitHub Flow中的定位是一致的。而在Gitlab Flow中,master分支不在对应生产环境,而是对应测试环境,但是其角色不同于Git Flow中的develop分支。master分支可以负责集成多个feature分支,但与Git Flow不同的是,Gitlab Flow秉承持续集成理念,不论是单个还是多个feature分支的merge行为均会触发后续的集成和交付。 如下抽象模型:

有tag触发持续集成和交付行为是Gitlab Flow相对于Github Flow和Git Flow的另一个不同点,后两者均是有master分支merge行为触发的,而Gitlab Flow的per-prod分支代码经过一系列严格的测试后背merge到prod分支,同事添加交付的tag,随后继续集成系统根据此tag进行后续的交付流程。 上述三种分支管理策略只是提供了一种思维轮廓,具体到实际工作中还需要根据自身业务和团队的实际情况做调整。比如业内对于有tag触发持续集成的模式存在一定争议,如果顾虑安全性的话,可以在Gitlab Flow的基础上,将监听tag修改为类似Git Flow的监听prod分支的merge行为;再比如在Git Flow基础上衍生出的One Flow等