现代软件开发过程中要实现高效的团队协作,需要使用代码分支管理工具实现代码的共享、追溯、回滚及维护等功能。目前流行的代码管理工具,包括CVS,SVN,Git,Mercurial等。
相比CVS和SVN的集中管理,Git具有非常明显的优势,例如:去中心化的代码管理方式减少了开发者对中心服务器的依赖,每个成员在本地都有一个完整的代码库,在不联网的情况下也能提交代码;不同于SVN中的每个分支具有独立的代码,Git中的每一个分支只是指向当前版本的一个指针,Git的分支策略使创建和合并分支变得快捷灵活。
从百度指数,也可以看到Git的优势被越来越多的人所认可。
Git的优势
- Git 可以在本地进行提交以支持离线工作;
- Git 可以在本地创建分支并且没有命名空间冲突的问题;
- Git 可以让提交通过 Pull Request 的方式进行,不需要所有的开发者都有主仓库的写权限;
- Git 在优化性能时选择了合并分支作为主要的性能衡量指标,将合并分支变成了成本非常低的操作以鼓励分支的使用;
- Git 通过 SHA-1 哈希来保证仓库中数据的可靠性,通过 SHA-1 就可以对数据进行校验,抵御了来自攻击者的恶意篡改;
Git作为分布式的代码管理工具,越来越多的团队开始使用它并逐步替代集中式的SVN 或 TFVC,同时也面临新的挑战。
版本管理的挑战
大家工作在同一个仓库上,那么彼此的代码协作必然带来很多问题和挑战,如下:
- 如何开始一个Feature的开发,而不影响别的Feature?
- 由于很容易创建新分支,分支多了如何管理,时间久了,如何知道每个分支是干什么的?
- 哪些分支已经合并回了主干?
- 如何进行Release的管理?开始一个Release的时候如何冻结Feature, 如何在Prepare Release的时候,开发人员可以继续开发新的功能?
- 线上代码出Bug了,如何快速修复?而且修复的代码要包含到开发人员的分支以及下一个Release?
大部分开发人员现在使用Git就只是用三个甚至两个分支,一个是Master, 一个是Develop, 还有一个是基于Develop打得各种分支。这个在小项目规模的时候还勉强可以支撑,因为很多人做项目就只有一个Release, 但是人员一多,而且项目周期一长就会出现各种问题。
Git代码分支模型
在使用Git管理代码以及多人协作的开发模式下,一个团队甚至一个公司对Git的使用有统一规范的工作流程尤为重要。
开发团队遵循统一的规则执行功能开发,问题修复,分支合并,版本迭代及发布等操作,可以使团队合作变得平滑顺畅,项目有序向前推进,我们把组织内这样的工作流程(workflow)称为Git代码分支管理模型
主流的git代码分支管理模型:
- Git flow
- GitHub flow
- GitLab flow
- TBD flow
1. Git flow
Git flow存在两个长期的独立分支:主分支master和开发分支develop,
- 主分支: 用于版本发布,主分支的每个版本都是质量稳定和功能齐全的发布版。
- 开发分支: 用于日常开发工作,存放最新的开发版代码。当开发分支的代码达到稳定状态并可以发布版本时,代码需要被合并到 master 分支,然后标记上对应的版本标签(tag)。
如果需要开发新的功能或者解决代码中的问题,则创建辅助分支来解决问题,辅助分支常用于:
- 功能开发(Feature),
- 版本发布(Release),
- 问题修复(Hotfix),
在辅助分支上的工作完成后,辅助分支将被删除。
Feature分支
目的是开发新模块或新功能以满足客户需求,从develop分支创建,开发结束后只需要合并回develop分支,并不需要合并回master主分支。
Release分支
是用于准备发布的版本分支,从develop分支创建,创建时已经包含了发布所需要的所有功能,所以在这个分支上不再开发新功能,仅对这个预发布版本进行修复问题,创建文档及其他与发布相关的工作,一切就绪后将Release分支合并回master主分支并打上相应的版本号标签(Tag),同时也合并回develop分支。
创建单独的Release分支可以避免在不同发布版本上的工作互相受影响,例如团队A准备发布版本1.0的同时,团队B正在进行版本1.1的功能开发,二者相互独立,不会互相影响。
Hotfix分支
通常用于紧急修复当前发布的版本中出现的严重问题,从发布版本的标签或master主分支创建,问题修复后合并回master主分支并打上新的版本号标签(Tag),同时也合并回develop分支或者正在进行中的Release分支。
创建单独的Hotfix分支可以避免打断正在进行中的各项开发工作,客户也不需要等到下一个发布周期才能拿到修复。
优点&缺点
Git flow需要同时维护两个甚至更多分支,Hotfix分支从master创建,Release和Feature分支从develop创建,工作完成后又需要将代码合并回 develop 和 master。
在实际应用中,很多开发者会忘记合并回 develop 或者 master,并且各辅助分支之间互相独立,如果从master上pull代码不够及时,一方面可能造成某个分支长期使用已经过时或者错误的代码,另一方面如果与master相隔较远,合并分支时可能会有大量代码冲突,往往需要花费很多时间来消除代码冲突,并且非常容易出错,影响项目的持续集成。
Git flow的优点在于流程清晰,分支管理严格,适用于发布周期比较长的“版本发布”,发布周期可能是几周,几个月,甚至更长时间。
由于保持两个长期分支同步的开销较大,所以Git flow并不适用于快速的“持续发布”,ThoughtWorks还专门将Git flow列为不被推荐的技术,建议彻底停止使用。
综合考虑了开发、测试、新功能开发、临时需求、热修复,理想很丰满,现实很骨干,这一套运行起来实在是太复杂了
2. GitHub flow
GitHub flow是由Scott Chacon于2011年提出的代码分支管理模型,这是GitHub官方推荐的开发流程,以快速部署为目标,目前大部分开源项目都遵循这一流程。
Github flow最大的特点是只有一个长期分支,即主分支master,且主分支始终保持可发布状态。
从master上创建新分支进行功能开发、问题修复等,这些分支通过pull request将代码合并到master。为了保证主分支的代码质量,master的权限只开放给一部分人。
Pull request是请求别人pull你的代码库(repository),也就是把开发分支的代码经过代码评审并通过测试后,让有权限的管理员合并回master。
不过在实际情况中,代码评审不可能检查出提交的代码中的所有问题,所以对于每次提交的代码进行自动化测试,
主分支代码的自动化部署尤其重要,自动化测试能在产品部署前及时发现一部分问题,如果产品部署之后发现严重问题,自动化部署可以在最短时间内把产品回滚到上一个版本。
优点&缺点
Github flow的优点在于流程简单灵活,不需要考虑及管理太多的分支,适用于需要快速集成及“持续发布”的项目,这类项目可能需要每天发布一个版本,甚至一天发布多个版本。但是对于应用场景比较复杂的情况,例如:多个环境下的产品部署,多个版本的发布或问题修复,只有一个master便会显得力不从心。
github flow这种方式,要保证高质量,对于贡献者的素质要求很高,换句话说,如果代码贡献者素质不那么高,质量就无法得到保证。
3. Gitlab flow
GitLab flow是由GitLab 的 CEO Sytse Sijbrandij 于 2014 年正式发布的代码分支管理模型,属于GitHub flow的演进版本。
与GitHub相同之处是也存在一个长期主分支master,从master上创建新分支进行功能开发、问题修复等,结束后合并回master。
与GitHub不同之处是GitLab flow又考虑多环境部署等现实因素,增加production产品分支用于在不同的环境下部署产品,或者从master的稳定版本创建release发布分支用于发布软件。
如果在产品分支或者发布分支发现问题,就从对应版本分支创建修复分支,修复完成之后,GitLab flow遵循 “上游优先” 的合并策略,也就是将代码先合并到 master,再合并到下游的production或release分支。
和Github flow类似,master的修改权限只开放给部分人,开发分支的工作完成后,代码通过merge request(类似于GitHub flow中的pull request)请求有权限的管理员把代码合并(merge)回主分支
4. TBD flow
TBD (Trunk-based Development) flow是由Paul Hammant于2013年提出的模型。
TBD flow最大的特点是所有开发都基于主干trunk,不再有长期的开发分支,要求所有的提交尽快回到主干,这样可以共享最新的代码,并且能尽可能地减少合并冲突。如果需要发布版本,可以基于trunk直接生成新的分支用于发布。
TBD flow没有pull或者push request,要求开发人员尽快把代码提交到主干分支,但是TBD flow缺乏严格的流程来保证每一份提交代码的质量,如果一些项目开发人员众多且水平不一,同时工作在主分支上可能会在产品发布时才发现不可预知的问题,
所以TBD flow更适用于需要快速迭代的产品,如果在主干分支上发现问题,可以快速进行修复再合并回主干分支。
5. TBD++ flow
TBD++ flow是Arrus公司软件研发部门从2015年开始一直沿用的Git分支管理模型,产品项目的客户主要是电信级服务运营商,每个国家或地区的需求在主要功能上一致,但在客户定制化方面又存在不少差异,同时项目开发周期较长,整个周期一般在3个月到2年之间,软件产品在项目前期需要有快速的迭代,在项目后期需要有稳定的发布版本。(PS: 前面这些因素是选择该模型的重要考量因素,产品型开发,主线功能大体一致,维护客户多,发布周期固定且稍长)
TBD++ flow以敏捷开发为核心,同时吸收了以上几个主流模型的优点,主要特点如下
1. 基于功能的主分支
只存在一个长期的独立分支,即主分支master,主分支上功能齐全,通过自动测试保证基本功能运行正常,因为自动测试覆盖不全面或者手动测试不及时,所以无法保证主分支的每个版本都是质量稳定的发布版,但是可以根据功能的完成程度直接从主分支上创建迭代版本用于针对不同客户或者不同时期的功能演示。基于master开发功能或者修复问题需要用到以下两个辅助分支:
- Feature分支:为了开发新模块或新功能以满足客户需求,从主分支上创建Feature分支,但是并不要求Feature分支上所有的提交尽快回到主分支,开发完成并且通过代码评审及功能测试后才能合并回master主分支。为了共用主分支上的最新代码以及避免合并代码时解决代码冲突引起的额外开销,在功能开发过程中Feature分支需要始终与master保持同步。
- Bugfix分支:基于主分支创建Bugfix分支修复主分支上发现的问题,修复完成并且通过代码评审后代码合并回master主分支。
基于主分支的Feature分支和Bugfix分支完成后,开发者直接将代码合并回主分支master,不需要像GitLab或GitHub那样依赖于少数几个有权限的管理员,这是因为如果一个项目中开发人员比较多的话,管理员没办法做到对每部分代码都熟悉或掌握,所以代码质量交由代码评审和功能测试来掌控,合并代码回主分支的操作由开发者自己完成。
主分支上的新代码有时候可能因为评审或测试不全面而带来新问题,例如破坏其他功能模块,甚至影响整体功能。为了能尽早发现问题,主分支上的每次提交都会触发系统级自动化测试,并且周期性地对主分支进行人工测试。一旦发现问题,主分支的专职配置管理员(Software Configuration Manager,SCM)将根据问题的严重性和紧迫性决定是否需要直接回退引起问题的提交,或者基于master创建bugfix分支进行问题修复。
2. 基于发布的Release分支
Release分支负责对外发布软件产品,每个Release分支也会配备专职版本配置管理员SCM,SCM具有对Release分支的最高管理权限。当master上已经包含了某个发布所需要的所有功能,并且没有已知的严重问题,此时由SCM从主分支上创建Release分支准备系统集成测试,和Git flow相同,在此分支上不再进行新功能的开发,仅在这个分支上进行修复问题,创建文档,客户参数配置及其他与发布相关的工作,这些代码同时也需要合并回master以确保主分支功能的完整性。
在每个Release分支正式发布前可能还需要将主分支上的一部分关键问题的修复选择性地同步(Cherry-pick)到Release分支,这个操作也是由SCM完成。
Release分支上的工作一切就绪并通过系统集成测试后,SCM在Release分支上打上相应的版本号标签(Tag)进行发布,这点和Git flow在主分支上进行发布不同。
软件产品发布之后,如果发现紧急或者严重的问题,此时需要基于版本发布时的Release分支标签创建Hotfix分支来修复此类问题,问题修复后合并回该Release分支以及其他同样需要此修复的Release分支,并打上新的版本号标签(Tag)用于发布,同时代码也需要合并回master以确保主分支的健壮性。
选择合适的分支模型
Git代码分支管理模型各具特点,流程只是一个辅助工具,没有最好,只有最合适。
- 如果开发团队规模较小又比较分散,产品发布周期较短(例如:初创公司,或者开发的是一个网站或 Web 应用程序,在一天内可能需要发布多个版本),可以选择GitHub flow或者GitLab flow;
- 如果开发团队规模较大,产品发布周期较长(例如:团队超过20人,采用了月度或季度发布周期,并且由一个团队负责并行开发多个项目),可以选择Git flow,发布周期较短可以选择TBD flow;
- 如果开发团队规模大,产品发布周期长,同时对敏捷的要求比较高,可以考虑TBD++ flow。每个组织根据产品、项目、人员的特点找到最合适的模型才是共同的目标。对于某个长期产品的开发和客户版本维护场景,这种分支是笔者比较推荐的。
以上这些分支策略,仅仅是作为大家实践的参考,不同的开发模式和发布节奏,以及团队的人员水平,基础设施水平等都是选择分支模型的参考因素。
参考
- 无需分支基于主干的开发是团队健康的重要标志https://www.infoq.cn/article/tFwoy4gko3vJqp5oYYEO
- 别再推荐 Git Flow 了:https://www.infoq.cn/article/i7m3UdTFLu1Lv2ai6abv
- 一个成功的Git分支模型(译文):https://segmentfault.com/a/1190000018087325