跳转至

04 一切的源头,代码分支策略的选择

记得大概是一年前吧,我与好友老吴喝茶聊天时,讨论到:高效的持续交付体系,必定需要一个合适的代码分支策略。

我告诉老吴:“采用不同的代码分支策略,意味着实施不同的代码集成与上线流程,这会影响整个研发团队每日的协作方式,因此研发团队通常会很认真地选择自己的策略。”

老吴是一名有多年开发经验的资深架构师,当时正好要接手一个框架团队,从个人贡献者向团队管理者转型。他个人对代码管理工具可谓熟之又熟,甚至连“老古董”的CVS都可以跟你聊半天。但他在为团队制定代码分支管理策略时,还是慎之又慎,足见其重要性。

最后我们发现,要确定选用哪种代码分支管理策略,需要先假设几个问题,这几个问题有了答案,也就代表你找到了适合的方向。

你需要思考的几个问题如下:

  1. Google和Facebook这两个互联网大咖都在用主干开发(Trunk Based Development,简称TBD),我们是不是也参照它俩,采用主干开发分支策略?
  2. 用Google搜索一下,会发现有个排名很靠前的分支策略,叫“A successful Git branching model”(简称 Git Flow),它真的好用吗?团队可以直接套用吗?
  3. GitHub 和 GitLab 这两个当下最流行的代码管理平台,各自推出了 GitHub Flow 和 GitLab Flow,它们有什么区别?适合我使用吗?
  4. 像阿里、携程和美团点评这样国内知名的互联网公司,都在用什么样的分支策略?

今天,我想再沿着当时的思考路径,和你一起回顾和总结一下,希望能够带你全面了解代码分支策略,帮助你做出合适的选择。

谈谈主干开发(TBD)

主干开发是一个源代码控制的分支模型,开发者在一个称为 “trunk” 的分支(Git 称 master) 中对代码进行协作,除了发布分支外没有其他开发分支。

Google和 Facebook都是采用“主干开发”的方式,代码一般直接提交到主干的头部,这样可以保证所有用户看到的都是同一份代码的最新版本。

“主干开发”确实避免了合并分支时的麻烦,因此像Google这样的公司一般就不采用分支开发,分支只用来发布。

大多数时候,发布分支是主干某个时点的快照。以后的改Bug和功能增强,都是提交到主干,必要时 cherry-pick (选择部分变更集合并到其他分支)到发布分支。与主干长期并行的特性分支极为少见。

由于不采用“特性分支开发”,所有提交的代码都被集成到了主干,为了保证主干上线后的有效性,一般会使用特性切换(feature toggle)。特性切换就像一个开关可以在运行期间隐藏、启用或禁用特定功能,项目团队可以借助这种方式加速开发过程。

特性切换在大型项目持续交付中变得越来越重要,因为它有助于将部署从发布中解耦出来。但据吉姆 · 伯德(Jim Bird)介绍,特性切换会导致代码更脆弱、更难测试、更难理解和维护、更难提供技术支持,而且更不安全。

他的主要论据是,将未经测试的代码引入生产环境是一个糟糕的主意,它们引发的问题可能会在无意间暴露出来。另外,越来越多的特性切换会使得逻辑越来越混乱。

特性切换需要健壮的工程过程、可靠的技术设计和成熟的特性切换生命周期管理,如果不具备这三个关键的条件,使用特性切换反而会降低生产力。

根据上面的分析,主干开发的分支策略虽然有利于开展持续交付,但是它对开发团队的能力要求也更高。

主干开发的优缺点如表1所示。

表1 主干开发的优缺点

谈谈特性分支开发

和主干开发相对的是 “特性分支开发” 。在这个大类里面,我会给你分析Git Flow、GitHub Flow和 GitLab Flow这三个常用的模型。

第一,Git Flow

我们在Google上查关键词“branch model”(也就是“分支模型”),有一篇排名比较靠前的文章“A successful Git branching model”,它介绍了Git Flow模型。

Git刚出来的那些年,可参考的模型不多,所以Git Flow模型在2011年左右被大家当作了推荐的分支模型,至今也还有项目团队在使用。然而,Git Flow烦琐的流程也被许多研发团队吐槽,大家普遍认为hotfix和 release 分支显得多余,平时都不会去用。

图1 Git Flow示意图

第二,GitHub Flow

GitHub Flow 是 GitHub 所使用的一种简单流程。该流程只使用master和特性分支,并借助 GitHub 的 pull request 功能。

图2 GitHub Flow示意图

在 GitHub Flow 中,master 分支中包含稳定的代码,它已经或即将被部署到生产环境。任何开发人员都不允许把未测试或未审查的代码直接提交到 master 分支。对代码的任何修改,包括Bug 修复、热修复、新功能开发等都在单独的分支中进行。不管是一行代码的小改动,还是需要几个星期开发的新功能,都采用同样的方式来管理。

当需要修改时,从 master 分支创建一个新的分支,所有相关的代码修改都在新分支中进行。开发人员可以自由地提交代码和提交到远程仓库。

当新分支中的代码全部完成之后,通过 GitHub 提交一个新的 pull request。团队中的其他人员会对代码进行审查,提出相关的修改意见。由持续集成服务器(如 Jenkins)对新分支进行自动化测试。当代码通过自动化测试和代码审查之后,该分支的代码被合并到 master 分支。再从 master 分支部署到生产环境。

GitHub Flow 的好处在于非常简单实用,开发人员需要注意的事项非常少,很容易形成习惯。当需要修改时,只要从 master 分支创建新分支,完成之后通过 pull request 和相关的代码审查,合并回 master 分支就可以了。

第三,GitLab Flow

上面提到的GitHub Flow,适用于特性分支合入master后就能马上部署到线上的这类项目,但并不是所有团队都使用GitHub或使用pull request功能,而是使用开源平台GitLab,特别是对于公司级别而言,代码作为资产,不会随意维护在较公开的GitHub上(除非采用企业版)。

GitLab Flow 针对不同的发布场景,在GitHub Flow(特性分支加master分支)的基础上做了改良,额外衍生出了三个子类模型,如表2所示。

表2 GitLab Flow 的三个分支

图3 带生产分支的GitLab Flow

图4 带环境分支的GitLab Flow

图5 带发布分支的GitLab Flow

GitLab Flow的特性分支合入master用的是“Merge Request”,功能与GitHub Flow的“pull request”相同,这里不再赘述。

通过Git Flow、GitHub Flow和 GitLab Flow(3个衍生类别) 这几个具体模型的介绍,我给你总结一下特性分支开发的优缺点。如表3所示。

表3特性分支开发的优缺点

选出最适合的分支策略

上面我跟你讲到的分支模型,都是IT研发领域比较流行的。虽然有些策略带上了代码平台的标识,如GitHub Flow,但并不意味着该策略仅限于GitHub代码平台使用,你完全可以在自己搭建的代码平台上使用这些策略。

接下来,我就总体归纳一下什么情况下应该选择什么样的分支策略。如表4所示。

表4 不同情况适用的代码分支策略

国内互联网公司的选择

GitLab作为最优秀的开源代码平台,被多数互联网大公司(包括阿里、携程和美团点评等)所使用,这些大厂也都采用特性分支开发策略。当然,这些大公司在长期持续交付实践中,会结合各自公司的情况做个性化的定制。

比如,携程公司在GitHub Flow的基础上,通过自行研发的集成加速器(Light Merge)和持续交付Paas平台,一起完成集成和发布。

再比如,阿里的AoneFlow,采用的是主干分支、特性分支和发布分支三种分支类型,再加上自行研发的Aone协同平台,实现持续交付。

总结

今天,我主要给你介绍了各种代码分支策略的特性。

你应该已经比较清晰地理解了“主干开发”和“特性分支开发”两种策略的各自特性:

  1. “主干开发”集成效率高,冲突少,但对团队个人的开发能力有较高要求;
  2. “特性分支开发”有利于并行开发,需要一定的流程保证,能保证主干代码质量。

相信在没有绝对自信能力的情况下,面对绝大多数的场景,企业还是会选择“特性分支开发”的策略。所以,我给你介绍了几种主流的特性分支方法,并对比了各类策略的优劣,以及它们适用的场景。

接下来,你就可以根据自己所在项目的具体情况,参考今天的内容,裁剪出最适合自己团队的分支策略了。

思考题

  1. 开源性质的项目,为什么不适合用主干开发的分支策略?
  2. 如果你所在的团队只有5人,而且迭代周期为1周,你会采用什么样的分支策略?

欢迎你给我留言。

精选留言(15)
  • 康美之心 淇水之情 👍(30) 💬(2)

    微服务架构下,比较适合主干开发,一个微服务(含1-4个API)根据复杂性和规模通常由1-3的开发进行开发(含单元测试的开发),1位测试进行API自动化测试开发,单元测试和API测试都集成到Pipeline上,一旦变动代码提交到master上后,就自动启动Pipeline上的build,在build这里会自动完成覆盖率100%的单元测试,单元测试通过,自动触发FVT deployment,部署成功后,自动触发FVT API自动化测试,FVT测试通过后;自动打出上线的tag号,并把这个tag号的部署到UAT,UAT部署成功后,自动触发UAT的API自动化测试,测试通过后,这个UAT的tag的就可以部署上线了。

    2018-07-14

  • 禾子先生 👍(8) 💬(1)

    对于第二个问题,我的思考是使用github flow,虽然追求效率,但必须保证线上版本是一个稳定。大家都在开发分支中进行开发,快速测试和迭代,合并到master时冲突也少。也考虑过使用主干开发,不过但从稳定角度来说,还是选择了前者

    2018-07-13

  • bullboying 👍(4) 💬(2)

    在自动化测试还没怎么做到位的情况下,为了控制合并到master的都是经过测试的代码,我们增加了一个SIT分支。每次有新特性需要开发时,从master分支check out一个特性分支进行开发,可能涉及到多人协同开发。自测完成后先发起merge request到SIT分支,如果有冲突则不允许merge,以实现不同特性分支间的隔离。如果没冲突且有集成测试人员空闲,则完成merge并安排测试,测试通过后由masters再发起merge request将特性分支合并到master。因为之前控制了冲突,所以第二次合并理论上是没有冲突的。现在纠结的几个问题,一是想要限制不能从SIT分支pull,否则就达不到多个特性分支隔离的效果,全靠开发人员自觉;二是因为隔离冲突是为了限制在制品,但导致master和SIT分支上的代码其实是不同的,是否需要测试两次?

    2018-07-18

  • 徐卫 👍(3) 💬(1)

    你好,问下。老师帮我看下理解对不对。主干开发是否只有一个分支,开发的代码提交到这个分支,发布也是用此分支。文中讲到的特性切换怎么做的? 我个人理解是在那个发布的版本上打标签,特性切换是从tag上拉出一份代码部署?

    2018-07-12

  • 董永刚 👍(2) 💬(2)

    分支类型中,带生产分支,带发布分支,带产品分支的分别是什么样的场景呢?

    2018-07-17

  • 纳米 👍(2) 💬(2)

    您好 我是一个非开发的人员。弱弱问下,最后表里总结的生产分支 环境分支中,开发人员自身是check out哪个分支代码出来开发 又是往哪个分支集成呢。能否在这两个分支上帮细化下。非常感谢。 思考题2 我理解 既然人很少 迭代周期也较为宽松 可能这一周大部分人都工作在一个功能或者版本上 是不主干开发反而也可以。github flow应该肯定是ok的。

    2018-07-12

  • 白天不懂爷的黑 👍(2) 💬(1)

    老师,您好,最近公司想用gitlab做配置中心,请问贵公司gitlab的高可用是怎么做的呢?谢谢

    2018-07-12

  • smartzs 👍(1) 💬(1)

    老师,主干开发 和 带发布分支模型 很像啊,带发布分支约等于主干开发了吧?

    2018-12-11

  • 小胖胖 👍(1) 💬(1)

    gogs被gitlab 应该选择哪个?有什么区别吗

    2018-07-13

  • 初七之月亮 👍(1) 💬(1)

    带环境发布分支方法的多数适用场景是啥呢?是不是有多少套环境就多少套分支啊?

    2018-07-12

  • Geek_gthxw2 👍(1) 💬(1)

    我们团队主干和开发两个分支并过来并过去,我该怎么解释这是种什么不好的方式呢。。。

    2018-07-12

  • 周小桥 👍(0) 💬(1)

    老师好,现在我们的一个系统是以产品的方式编写,但是是以项目的方式买给不同的客户,这中间涉及到不同客户的不同需求 ,没办法都满足,会有差异,有的是同一模块 ,有的是定制需求!现在代码都是一套, 维护代码特别麻烦,满足了这里满足不了哪里,特别是那种几个月前部署的项目出了问题,有改动或者新功能升级 很容易出现问题,功能冲突等等…现在没有找到一种特别好的管理代码的方式,希望老师指导!

    2018-07-20

  • 王浩槟 👍(0) 💬(1)

    我司用的还是SVN,没用过git。想问: SVN是不是很落后了?转换到git上有价值吗?如果转该怎么处理更平滑更低代价?

    2018-07-17

  • 张明云 👍(0) 💬(1)

    我们公司是平板方案商,APP开发是敏捷模式,平板大项目是IPD模式,并且平板发布时会预置这些APP,但APP在某个版本上只要满足了平板要求的特性,就可以继续迭代新版本了,但虽然APP预置到平板的版本已经发布了,只要平板还在测试,出现比较严重的问题还是要继续改动。并且有时还会配合平板的硬件特性开发预研版本,相当于APP需要同时维护几个版本。请问老师这种情况用哪种分支模式好呢?

    2018-07-14

  • 图·美克尔 👍(0) 💬(1)

    我们每个环境都要持续集成和持续发布…保证每个环境都是稳定和可用。最近有个问题是,子项目上提交后会触发到总项目的然后所有子项目的服务器都会重新部署…

    2018-07-13