大型项目gitflow实践

144
作者 兔龙象
2017.04.02 09:12* 字数 8267

首先,这不是一篇讲解gitflow工作流的文章,也不是讲解git工具命令的文章(但是看这篇文章之前一定要熟悉git和gitflow),作为比较重量级的产品,发布周期从最早的3个月一版本,到1个月一版本,再到半个月一版本,我回顾一下我们使用gitflow的全过程,从svn到git到gitflow,总结一些遇到的问题和我们的做法,还有结合敏捷的一些思考等,供大家参考。

我从6个方面介绍一下使用gitflow的过程。
1、项目背景,简单了解一下;
2、svn迁移git的过程,简单介绍迁移的经过;
3、正式使用gitflow前的尝试,如何尝试,尝试结果等;
4、研发模式调整,为什么调整,如何考虑的;
5、敏捷思维,gitflow不单单是一个工具,更是一种思维转变;
6、实践gitflow过程中的典型问题等。

一、项目背景

我们的产品作为公司最重量级的产品,尝试使用git时(2016年10月)研发团队总体107人左右,研发经理6人、需求12人、架构师1人、系统分析师1人、测试26人、开发61人,整个团队负责全国16个省的业务交付,产品研发和维护。

工作量:平均每个月反馈150个左右新需求,60个左右缺陷,研发团队能够完成50%左右的新需求,基本上能完成全部紧急的缺陷,外加一些产品主动规划内容和各地突发的事件(如第三方对接等)。

研发模式:1个主干(负责全国)+7个分支模式(负责地区),主干负责全国性需求和产品主动规划内容,主干3个月一版;各分支负责各个地区的需求、个性化需求和发布后缺陷,1个月一版,分支发布后将代码合并到主干。其中有一个分支在大连,一个分支在成都。


旧有的研发模式

svn下主干分支模式

使用svn遇到的问题

1、打分支极其麻烦:每次主干发布后都要打出6个分支,旧的分支废弃,源码大小10G左右(纯源码,不包含文档,jar包等),svn打分支的方法就是copy一份,所有开发人员至少1天来重新搭建环境,eclipse每次build就要几个小时(已经上了固态硬盘的情况下)。

2、合并代码麻烦:共7个团队,6个团队每个月要将代码合并到主干,各种冲突报错,每个发布周期的最后一个月,110人全部在主干上操作,平均每天测试都会提出100多个bug,经常改一个bug可能引起几个其他bug(技术债务太多,产品已经开发了7年,团队大部分都是初工,几乎每次发版前都是通宵)。

3、异地专线网络不稳定:7个团队中,有一个团队在大连,有一个团队在成都,专线带宽有限,也不稳定,svn提交经常卡住,后来在大连单独建立一个svn服务器,定期从大连svn服务器提交到北京svn服务器,网络问题解决了,但是提交日志没办法合并,大连提交过来的日志全部丢失。

4、日志无法保留:除了主干,其他分支最终是要废弃的,分支合并到主干就是正常提交,所以分支的所有提交日志是没办法保留的(其实是有保留,只是每次都在删除的几十万个文件中很难查到)。

研发模式的问题

1、主干3个月一版,全国性需求响应慢,从上面图中可以看到,主干开发的3个月过程中,分支随意合并,导致主干没办法发布,只能卡到最终的时间点发布。全国性需求最近极其频繁,等不到3个月,基本上1个月一版,甚至比分支还要频繁,导致主干往分支合并的情况很多。

2、本质的问题,把产品当成了项目开发,不到20人的主干团队开发产品规划功能,剩余90人都在忙地区交付,2:9的人员配比,重交付轻研发,目标是快速交付,客户说啥做啥,结果质量很不理想,发布后问题非常多。业务专精不够,没有人把软件当成自己的事,没有人对产品熟悉,分支团队只关注客户满意,提什么做什么,整体缺少统筹安排,无业务上统一管理,各地需求重复,冲突等。

为了解决这些问题,经过5个月左右的git研究(大团队突破还是异常谨慎的),最终决定使用git替换svn,结合gitflow,进行研发模式的调整。

工具层面,主要是打分支、切换分支、合并等操作方便,打一个分支瞬间,切换分支10分钟左右(想想原来打分支搭建环境要1-2天)。

研发模式方面,一方面为了快速交付,一方面为了改变产品研发模式,按地区负责模式调整为按业务负责模式。

从2016年9月开始,到2017年4月基本顺畅,从svn到git,从地域划分到业务划分,从主干分支到gitflow......

二、svn迁移git

目标:迁移后的日志保留(日志),不能影响现有工作(稳定),大家容易接受(平滑)

困难:文件太多,上百人的团队工作六七年,文档27G,纯源码10G多(不包括jar等)。

(1)经过2个多月的各种尝试,碰了不少钉子,最终成功完成迁移,前前后后用了2个多月,但最终整个迁移工具只运行大约16个小时就完成了。

(2)迁移用的工具是git-svn,日志一共大约16万,经过尝试后,因为速度、内存等原因,最后保留了6万的日志。

(3)遇到最多的问题就是迁移工具报错,比如目录太深就会报错;目录名称特殊就会报错;文件不完整读写不了就报错;工具对内存要求比较高,调整到64G内存才够。

最终迁移过程如下:

1、配置管理员将svn代码迁移到git上,并按照目前svn模型,在git上打好分支,从v3.6版本建立各个分支,主干命名master,各分支为branchA,branchB,branchC,以此类推。

2、在主干发布v3.6.1,并且在svn上合并完代码后,配置管理员会将此时主干代码完全迁移到git上(一晚上完成)。主干人员使用git工具下载源码并搭建环境,从此开始在git上开发。

3、各个分支团队继续在svn上开发,发布完当前版本后,开发人员将代码完全提交到git的分支上,然后使用git工具进行合并,合并后参与主干开发,至此全部开发人员在git上开发。

4、只迁移源码,其他数据(如文档)继续在svn上使用,svn和git并行同时使用,项目的文档有27个G。


svn迁移git

最后在配置管理员一晚上的通宵下,顺利的完成了主干的迁移,从此大家在git上进行开发。

三、gitflow前的尝试

1、git当svn使用

刚刚切换完毕git,开发模式完全和之前用svn一样,仅仅把git当svn使用,目标是全部切换到git上,对git工具使用熟悉,git工具使用熟悉后再调整。


git和svn的模式一模一样

看似简单的过程,也遇到了不少问题

1、工具使用问题,大家都习惯用myeclipse开发,公司也做了很多eclipse插件在老版本的myeclipse上,git插件是egit,在低版本的eclipse上功能有限,新版的egit只能在eclipse4.x的版本,大家升级myeclipse成本太高,不用myeclipse改用eclipse的话很多功能不方便(比如tomcat实时部署就不行,需要重启),最终也没有太好的方案,目前大家用老版myeclipse,在资源管理器里面用SourceTree或TortoiseGit提交。

2、合并工作只能一个人干,这个是之前没考虑到的,测试的时候也只是在自己机器上几个小文件之间测试,之前svn的时候每个人负责几个模块的合并,每个人都可以提交,git的megre只能一个人用,一下子将近1000个文件冲突(一个团队一个月的工作),只能每个人解决一点点,然后汇总到一个人机器里面,然后提交,很麻烦。

3、还有比较难受的也最好解决的,新东西都有一个熟悉过程,总会有人因为不习惯、不熟练、不清楚等等原因,导致做错了、或者浪费时间、或者产生不爽情绪、或者有些抵触等等,解决办法就是随着时间的流逝,大家都熟悉起来了,也就习惯了,必然会有一段时间难以忍受(其实遇到90%的问题都是不熟悉工具导致的,工具使用熟悉了就好了,没有总结的必要)。

2、主干团队尝试gitflow

git工具使用没有问题了,找了一个大版本发布后,主干团队尝试采用gitflow和pull request,各分支依然使用传统方式开发,合并回主干方式不变。目标是熟悉、尝试gitflow和pull request,用这两个流程来管理代码,研发模式不变。pull request的目的是强制做代码复查,复查后才允许合并。

主干开发时,每个需求或功能打一个feature,粒度保持在一个版本发布即可,但尽量避免几个功能放一个feature中,feature命名规则用版本+功能名称方式,如:feature/v3.7.1-xxx


结果

1、整体gitflow尝试不算成功,因为合并复杂,大家都担心打分支,合并带来问题,最终master,release都没有执行起来,在dev上测试完毕直接就发布了(大家都觉得重新打分支风险大)。gitflow的价值没有体现出来,也仅仅是开发新功能的时候,在feature上开发,然后合并到dev,不过feature的价值也没有发挥出来。

2、feature对我们的价值主要在于2点

(1)开发过程中开发功能相互不影响,功能没开发完也不会影响版本发布。
结果:由于管理不严格,研发能力不够等原因,有的时候开发人员在feature上完成开发就合并dev,合并后测试发现也就完成了50%,剩下大部分时间都在dev上改bug,最终相当于大家都在dev上开发,feature的价值没发挥出来。

(2)大一些的需求可以在feature上开发,可以跨几个版本发布,比如一个大需求要开发3个月,不会导致主干必须等3个月,可以提前投入开发,开发完了就合并到dev即可。
结果:整个模式还是“限定时间限定内容”的模式,原来大家一起冲上去加班1个月开发完100个需求,现在还是1个月100个,还要弄feature,还要合并等等,多了很多规范,自然效果不好。

3、pull request完全没弄起来,前面说的几个分支都没干起来,更别提pull request,大家正常提交合并都有很多问题,没人有时间做代码复查等。

4、大家整体都觉得gitflow不好,很多人不理解为什么弄这么复杂,为什么弄feature,我安安心心的开发多好呀,缺少讲解,缺少宣传。

这次只在主干团队做的尝试,虽然效果不好,但也是有效果的,年底最高执行对接工作频出,不停的下要求下明传,每个功能都是在feature上开发的,好处是我们没有合并到dev,而是合并到了各个分支,虽然合并工作量大了,分支交叉合并多了,但至少让我们没有停任何分支的情况下完成最高执行的各种对接工作(如果原来模式只能停下现有工作去做最高执行对接),主干的发布周期缩短到了1个月,甚至比分支还要短。

这次尝试也我们看到gitflow整体的好处,遇到的问题都是可以解决的,这个模式没有问题,只是我们使用的时候执行不够坚决,理解的不深。
(1)不应该上来就基于现状优化流程,应该结合团队能力做一些防御性的措施,先把流程固化下来再考虑优化,上来就优化,优化优化着就没了。
(2)gitflow虽然是一个工具,但为了使用工具,我们自己也要跟着变化,团队也要跟着变化,否则不可能依靠一个工具就能够把效率提升。

四、研发模式调整

要进行研发模式的调整,才能适合gitflow。

注意,我们不能为了gitflow而gitflow,前面也说了,研发模式调整其实早已筹划,只是正好和gitflow结合而已。


按地区转为按业务

1、由原来按地区负责,调整为按业务负责,单独有一个团队负责地区,原来负责产品人数:负责客户人数是2:9,产品当成了项目做,结果产品质量不高,问题多,做出来的东西不符合客户,个性化需求就做配置,冲突需求就做配置等等。现在调整为9:2,重视产品研发质量。

还有一个好处是减少了代码合并的冲突,负责地区的团队可以修改系统全部功能,比如原来负责广西的A团队修改了立案系统,负责河南的C团队也修改了立案系统,合并的时候就冲突了,处理冲突耗时极大。
现在调整为按业务负责,A团队负责执行业务,C团队负责立案,所有执行业务都由A团队修改,冲突的概率降低不少(虽然没有完全消除,完全消除依赖物理上的拆分,目前也正在朝这个方向努力)。

2、对内对外,团队分为对内和对外两种团队,对内的只负责业务研发,目标是把产品做的非常好;对外负责地区的团队,目标是客户满意,原则上只处理现场最紧急的问题和需求。
执行过程中,对外团队会不停的向对内团队扔需求和缺陷,对内团队根据自己的产品研发节奏排时间和版本,如果来得及就对内团队研发,如果来不及就对外的团队当作紧急事件自己直接处理,理论上最好都有对内团队研发,因为对产品更加熟悉,更加专业,也利于减少冲突。

当然,这些是我们的目标,执行过程中还是有很多问题的,典型的大家比较担心的问题:
1、对内团队的人觉得我们对内了,缺少与客户沟通的机会。实际只是工作职责变了,工作内容没变,依然需要大量出差,跟客户调研,也只有泡在客户身边才能做出更好产品。
2、对外团队的人觉得我为了客户满意,缺少写代码锻炼技术的机会。实际对外团队也要写代码,开发很多需求,也有很多机会锻炼排查问题能力,尤其性能问题,疑难杂症等,都是锻炼的机会。
其实对内对外只是工作职责的划分,不意味着工作内容调整,对内团队也需要走出去,对外团队也可以开发需求,没有太极端的划分。

类似的问题很多,这也是为什么需要大量宣传和讲解,消除大家的担心

最终决定要做,确认了最终方案,正好赶在春节前1个月,我们做了PPT,整理了文档,内容包括研发模式调整、gitflow讲解等等,给领导讲,给各团队的研发经理讲,给核心开发人员讲,给其他部门讲等等,讲了很多遍(我正式讲了10次以上),还是很有效果的,大家从初期有很多担心变为觉得可以尝试。

ok,我们确定了从春节长假后回来就按照gitflow工作流程开始研发工作。

五、敏捷思维

我们采用了原汁原味的gitflow工作流,没有进行任何删减(所谓的根据实际情况优化),执行过程中遇到了很多问题,也增加了很多环节、规范等。
gitflow模型如下,这里就不详解每个分支的作用了,不清楚的百度一下吧,说的非常详细。



首先,gitflow仅仅是一个工具,能够有效提高发布频率,让大型项目更加灵活,带来的不便就是有一定的学习成本,管理成本有所提高(需要配套的工具才能降低),提高效率方面需要结合很多其他方面才能提高。

1、灵活

我们的模是是每个版本要限定时间限定范围,比如1个月开发100个月需求,假如100个需求中有5个需求没开发完,你会选择做完了再发布,但是延期,还是选择不延期,但只发布95个需求?

大部分时候我们都想选后者,保证时间,可惜的是我们的工具不支持,代码已经提交了,bug没改完,就是发不了。此时gitflow给予了我们选择权,让我们有选择的机会。

这个是gitflow最大最大的优势,让发布更加灵活,gitflow会将每一个功能隔离开发,每个功能(或需求)都是一个feature,开发完了就合并发布,没开发完就暂时先不发,不会因为一个功能导致全部都发不了。

2、敏捷思维的转变

之前大家在一起讨论,在现在这种“限定时间限定范围”模式下,人永远是不够,活永远是干不完,人员能力无法快速提升,人员规模难以扩大,原来一个月加班加点熬夜能够完成80个需求,现在要求提高效率一个月完成120个,除了买床住在公司,就是住在公司旁边酒店了。

万幸的是,现实情况不是这样,首先提高效率的前提是目标是对的,120个就一定比80个好吗?我觉得不一定;其次,我们可以尝试改变我们的模式(幸好今年公司提敏捷升级,去年做的时候真难以推动)。

现实情况远比上面例子复杂,往往版本开始会根据团队规模规划需求,比如规划要做100个需求(实际客户反馈了200个),研发过程中会临时插入了50个,这150个当中可能有10个分析后可能不做了,可能有10个需求改动太大推迟到下个版本,可能因为做不完砍掉了50个......最后交付了60个,最终完成的这60个和最初的计划的100个,重合的可能也就40个(有时候会更低)。几乎每个版本都这样(数字是假的,比例是真的)。

其实在这种常态下,其实我们真正完成需求数量的多少已经不太重要了,完成需求的符合程度,划分需求优先级才是更重要的。这也是敏捷开发的思想,需要我们由一个“限定时间限定范围”的思维向“固定周期,不断迭代”的方向尝试。

限定时间限定范围,一个好的研发经理分解到足够细,日常跟踪到足够细,想尽办法掌控精准的进度,加班加点,大家保证完成任务,如下图:


传统模式

原来一个月加班加点做100个需求,敏捷和gitflow都不会让你多做到120个,但会让你更准确的完成这100个,甚至最终仅完成60个(其他的没价值抛弃了),我们追求未来的模式是这样的:


敏捷思维

敏捷让我们改变一个思维,不追求完成功能的多少(限定时间限定范围加班冲),而关注交付的价值(固定周期发布最有价值的),虽然很难,但不迈出第一步连机会都没有。

gitflow就是一个很有效配合敏捷的工具,开始固定每个月发布一版,做完多少发多少,没做完的放到下个版本发布,执行过程中因为一个月周期太长,需求太多,测试要一遍遍的回归(至少5次),导致整体效率和之前区别不大,后来定为半个月一版,需求少了,测试回归一遍没问题就ok了,效率提升显著。

如果真的不好理解,你就想想你在赶公交车的时候,这趟跟不上就要等下一趟,一趟车能装100人,30分钟一趟,你会什么感受?现在我们把这个车改小了,能装20人,5分钟一趟,就这个意思,没错,就是牛逼。

六、gitflow执行过程中的典型问题

虽然有这么优秀的版本管理工具(git),工作流程(gitflow),但执行过程中,依然有非常大的挑战,比如:

  1. 何时开始打feature,从发布点打feature还是中间点打feature?大家乱打feature怎么办?
  2. 很容易创建分支,分支多了如何管理?周期长了如何知道每个分支是干什么的?
  3. 哪些分支已经合并回了主干?什么时候合并?是必须改完bug再合并,还是合并后再修改bug?
  4. 如何进行release的管理?开始一个release的时候如何冻结feature,如何保证大家都比提交。
  5. 代码合并容易了,脚本怎么办?脚本是统一管理还是分开维护?
  6. ......

类似问题非常非常多,遇到问题我们内部沟通讨论,形成规范,要求大家遵守,慢慢的规范也比较多了(其实也是无奈,100多人水平参差不齐,不得不弄一些规范)。


流程规范

好在每个团队都有自己的管理方法,遇到问题积极的解决问题,比如有画到纸上管理的:


有画出流程自己团队内部讲解的:


下面说说我们实践过程中遇到的一些典型问题。

1、feature管理
基于之前的经验,每个feature都是一个独立的需求(或功能),一定要全部测试通过后才能合并到dev,否则后期就是大家都去dev上开发了,测试一遍遍的回归,和之前没区别了。
feature需要一个人或团队单独管理,或者有自动的可视化工具,我们没有工具,开始时一个人专门管理,结果干了不到2个星期就坚持不住了,放到每个团队专人管理,自己团队管理自己的feature,数量少了,每天站会沟通一下即可,不费时间,合并后的feature也及时删除,同一时间的feature数量基本固定在一个规模。
有的团队使用的是白板,有的用在线的一些工具,有的用excel。


feature管理

2、发布周期要短
目前定的是半个月一版本,发布周期长,每个版本需求多,加上历史遗留问题多,结果就是测试人员要一遍遍回归,甚至最后需要一周时间回归,也就是说一个月只有3周有时间开发,剩下一周都用来测试了。所以要缩短发布周期,目前定的是半个月一版,需求量少了,测试回归次数少了,效率自然提高了。

3、可视化预告
定好了各种发布时间,要及时通知各个团队,最好是可视化的方法,而不是一段段的文字,一段段的文字加上大家刚开始对gitflow理解不深,很容易搞混和弄错(尤其3地经常电话沟通),所以经过几次沟通和实践,还是可视化的一些方法比较好,清晰、简单,如:


可视化优于文字

4、数据库脚本管理
开始时我们激烈的讨论过每个feature是放到各个团队做,还是集中放到一个团队权权负责脚本。为什么会考虑一个团队权权负责脚本?因为之前几乎就这种模式,开发只关注代码,需要改数据库的时候告诉脚本负责人改一下就行,导致开发人员没有修改脚本的习惯和意识。结论还是以目标为导向,不根据现有实际情况来,每个团队独立负责自己的脚本,最后有一个总的脚本负责人负责整理脚本。

脚本提交时间,在feature合并后必须提交脚本,测试人员连带功能和脚本都测试完毕才算完毕,大家把脚本统一放到一个目录。开始的时候大家很不习惯,经常漏脚本,不提交脚本,怎么强调都没用,最终又是红包帮忙了,不按规范来就发红包,效果很好,虽然还有人做的不够好,但大部分人都按规范来了。

每个feature一个脚本目录,没有脚本的也要弄个空目录,最后发布了多少feature,就多少个脚本目录,发布前有人整理成批处理一键执行。


数据库脚本

5、固化流程
不论什么原因,定好的时间,总会有人不按规定执行,就是在你要进行dev上的合并测试时说我还有没合并完dev的,已经打出release了,告诉你有feature要合并dev,必须要给客户上......类似情况非常多,我们总结这种情况有2个方面:
(1)态度问题,就是不注意,无所谓,对gitflow有抵触的等等,过于硬性的手段效果很不好,我们的测试同学(为什么是测试,因为不按规范来测试是第一受害人)拉群让不按规范来的人发红包,这个效果就很不错,谁也不好意思总犯错误。
(2)现实困难,客户逼着要,真的是完不成,也有的就是临时加进来的,必须带上。此时大家要相互理解,谁都不想延期,谁都想按规范来,迫于各种困难不得不这样,双方各让一步,简单的一起通宵加个班就解决了,复杂的就先不发了,发布后马上发布一个patch解决等。

双方理解是前提,保证gitflow流程顺畅是底线,严格执行流程不是说我们僵化效率低,而是因为60多开发人员都在一个dev上提交合并代码,有一个需求不按流程来(需要根据实际情况判断风险)就可能导致整体延期,这就又回到了过去的模式。所以很多时候只能一事一议,控制变更也是研发经理的一个能力,灵活和风险之间寻求平衡。

总结来说

1、gitflow虽然只是一个工具,但背后隐含着意识的转变,意识不够敏捷,换gitflow只会增加管理的成本,思维敏捷了,不用gitflow也会有很多其他更好的工具和方法。

2、大的复杂的系统,如果不解决历史包袱永远效率上不来,想想100多人同时开发一个产品(真的是一个产品,一根主线,没有拆分),无论是用gitflow还是用别的流程模式都很难跑起来,只有从物理上将源码拆分出来,物理上拆成多个系统才能保证每个团队独立负责,团队间耦合少,才是腾飞的前提,不要指望gitflow能够一下解决很多问题,还需要周围很多技术和管理的配合。

3、以人为本,所有流程都是给人用的,最终一定是所有人都认可和接受的,而不是觉得好定个规范大家执行,所以有的时候推动和执行比提出想法更为困难,你的东西再好,大家用不起来也是白搭,执行过程中肯定有很多碰撞和质疑,大家相互理解就行,最后要感谢团队每一个人的付出,感谢领导的强力支持,大家一起进步,才能保证整体效率提高。

研发管理