Git分支管理

聊一下Git分支管理的策略,常见的有两种:Git Flow和GitHub Flow。

Github Flow

我们先从简单一点的Github Flow开始。

Github Flow顾名思义是用在github上的:

  • 首先有一个主分支,就是master分支,master分支是用来部署的,不可以在master分支上直接提交代码;
  • 每当需要修改或增加新功能时,开设新的分支,可以叫feature分支,也可以叫做其他分支,总之是开设新的branch进行开发;
  • 开发完成后发起Pull Request操作,申请将feature分支合并到master上;
  • 评审并接受Pull Request后,feature分支的代码就被merge到了master上,如果有冲突就解决。

Github Flow的好处是足够简单,只有一个固定的master分支。Github Flow适合发布频率非常高的场景,比如一周上线几十次,甚至一天上线几十次的情况。

Git Flow

Git Flow远比Github Flow复杂,我们先看一下下面的示例图。

  • 首先,有两个固定的主分支master分支和dev分支:其中master分支用来部署生产环境,master分支的代码和生产环境代码一致;dev分支用来开发,dev分支上保存最新的开发代码;
  • 为避免多人同时在dev分支开发产生干扰,dev分支和master分支一样,都不可以直接在上面提交代码;
  • 从dev分支开设feature分支进行新功能的开发,开发完成后将feature分支merge到dev分支上;注意,feature分支的代码还没有经过测试,dev分支上的代码不是稳定代码;
  • 当需要测试时,从dev分支开设release分支进行提测,改bug在release分支上进行;
  • 测试通过,将release分支merge到master分支,部署生成环境;将release分支merge到dev分支,保证dev分支代码的稳定;
  • 当需要紧急修改线上代码时,从master分支开设hotfix分支,开发、测试,测试通过后合并到master分支。

Git Flow的主要思想:

  • 两个固定分支master和dev一直存在,三个临时性分支feature、release和hotfix,使用完后可删除;
  • 新功能代码在feature分支上开发,在release分支上测试、改bug,合并到master分支上线。

Git Flow的敏捷流程:

  • 一个冲刺开始,先划分需要开发几个功能,为每个功能从dev分支开设feature分支,可能一个开发人员对应多个feature分支,也可能多个开发人员对应一个feature分支;开发人员在feature分支上开发代码;
  • 完成一个功能后,就把这个功能的feature分支合并到dev分支上进行开发联调;
  • 这个Sprint全部功能都完成后,从dev分支开设release分支,将release分支代码部署到测试环境进行测试,测试过程中发现的bug直接在release分支上改代码(dev分支上还是旧代码);
  • 测试通过后将release分支同时合并到master分支和dev分支。

我的实战

最后说一下我的敏捷开发实战,实战中我使用的是修改过的Git Flow,先说说Git Flow不满足我们要求的地方。

  1. 测试分支是动态的,测试环境部署哪个分支的代码成了让人头疼的问题。实战中存在这样的情况:release1正在测试中,release2又提测了,一套测试环境,两套代码,就意味需要不停切换分支进行测试,非常乱,也非常容易出错。或许你会说,准备两套测试环境不就行了,那如果release3也要同时测试呢?总不能几个分支同时测试我就需要准备几套测试环境吧,成本上考虑肯定不允许。
  2. 开发联调的问题,feature分支开发完成后合并到dev分支后,需要进行前后端联调,由于feature分支是非经过测试的,难免问题很多,而dev分支又不允许修改代码,其结果就是反复把feature分支merge到dev分支。

下面说一下我的实战:

  • 我们有三个固定分支:master分支、dev分支和test分支,四套环境:生产环境、准生产环境、测试环境和开发联调环境;生产环境和准生产环境部署master分支的代码,测试环境部署test分支的代码,开发联调环境部署dev分支的代码;和Git Flow一样,master分支、dev分支和test分支都不允许直接修改;和Git Flow最大的区别是我们增加了固定的test分支,这样可以保证时刻我们的测试环境都有源可寻;
  • 一个冲刺开始,从master分支开设sprint分支(相当于feature分支),以后一直在sprint分支上写代码,当需要开发联调时,把sprint分支合并到dev分支,当需要测试时,把sprint分支合并到test分支,当需要上线时,把sprint分支合并到master分支;
  • 如果多个冲刺同时进行,那么test分支上可能合并了多个sprint分支的代码,但是上线时这些sprint分支可能不是一起上线的,这就可能产生隐藏依赖的问题(例如:sprint1上的某个问题在sprint2上被改好了,test分支合并了sprint1和sprint2,测试是没有问题的,但是sprint1先单独上线就存在这个问题);所以,为了保证上线的安全,我们增加了准生产环境,准生产环境部署master分支的代码,提前进行验证;
  • hotfix分支的用法和Git Flow基本一样,区别在于hotfix分支也是先合并到test分支进行测试,验证无误后合并到master分支,部署到准生产环境在此验证,如果发现问题再次重复合并test分支和master分支的过程。

对比

最后再来对比一下:

  • Git Flow认为dev分支是主分支,dev分支就是最新的代码,需要上线时开设release分支进行测试,测试通过后把这部分代码合并到master分支,master分支基本上就是tag分支;
  • 我的定制Git Flow认为master分支是主分支,每次需要上线新功能就开设sprint分支(feature分支),dev分支和test分支其实是临时分支,它们分别表示开发联调环境和测试环境下最新的代码;所有代码都在sprint分支上新增和修改,最后合并到master分支上线生效。

Git Flow中代码先在feature分支上开发,然后又在release分支上改Bug,我认为太分散,不好;功能都在sprint(feature)分支上开发,虽然改Bug需要合并到test分支有点麻烦,但是如果我需要看一个功能都改了哪些代码,只需要查看sprint分支即可,一目了然。

Git Flow

  1. 从master分支开设dev分支;
  2. 从dev分支开设feature1分支,开始新功能1的开发;
  3. 从dev分支开设feature2分支,开始新功能2的开发;
  4. 新功能2代码开发完成,合并到dev分支;
  5. 从dev分支开设release分支,测试功能2的代码;
  6. 功能2的代码测试通过,将release分支合并到master分支和dev分支;
  7. 新功能1代码开发完成,合并到dev分支;
  8. 从dev分支开设release分支,测试功能1的代码;
  9. 功能1的代码测试通过,将release分支合并到master分支和dev分支;

我的实战

  1. 从master分支开设sprint1分支,开始冲刺1的功能开发;
  2. 从master分支开设sprint2分支,开始冲刺2的功能开发;
  3. 冲刺2的功能代码开发完成,从sprint2分支合并到dev分支进行前后端联调,联调过程发现问题修改sprint2分支的代码重新合并到dev分支;
  4. 前后端联调完成后,冲刺2的功能提交测试,从sprint2分支合并到test分支进行测试;
  5. 冲刺2修改测试过程中发现的问题,重新从sprint2分支合并代码到test分支;
  6. 冲刺2测试通过,合并代码到master分支上线;
  7. 冲刺1的功能代码开发完成,从sprint1分支合并到dev分支进行前后端联调;
  8. 冲刺1前后端联调完成,从sprint1分支合并到test分支进行测试;
  9. 冲刺1测试通过,合并代码到master分支上线;

从两个图中也能看出端倪:

  • Git Flow中有数字的节点很分散,也就是说我们经常要操作不同的分支,我感觉还是太复杂;

  • 我定制的Git Flow中有数字的节点基本都集中在sprint分支,也就是说开发人员主要聚焦于sprint分支,个人感觉会更清晰一些;

本质上两个流程最大的区别是release分支和test分支的区别。

开release分支的好处:可以直接release分支上改bug,很方便;

开release分支的不足:我认为这种模式下release分支需要快速测试完成,例如1-2天测试完成一个release分支马上上线,然后再测试下一个relase分支;假如release分支需要测试一周甚至更长时间,那么我们很难保证在测试这个release分支时有其他测试任务插入进来,这样就需要频繁切换测试环境的分支,容易造成混乱和错误。例如:线上发现问题需要hotfix,改完代码怎么办?需要把测试环境从release分支切换到hotfix分支进行测试,等hotfix上线后再切回到release分支。如果一个release分支还没有测试完成,又有一个release分支提测怎么半?要么第二个得等到第一个测试完成,要么在两个分支之间切换,都不好。

开test分支的好处:测试环境固定对应test分支,可以保证测试环境的稳定;

开test分支的不足:(1)改bug麻烦,每次修改代码都需要从sprint分支合并到test分支进行测试;(2)test环境同时共存的多个分支可能产生依赖问题,为保证单个sprint分支上线没有问题,需要引入准生产环境进行验证。