作者简介
新友,携程前端工程师,主要负责机票主流程和机酒预订流程相关开发工作,对安卓和React Native有浓厚兴趣。
Heter Li ,负责携程GitLab代码平台研发,致力于高效的持续集成事业。
一、前言
随着移动互联网时代的高歌猛进,产品的研发迭代速度变得愈来愈快,工程复杂度越来越高,这对产品研发过程提出了高质量、高效率、更灵活的要求。在研发团队的开发协作上,开发人员遵循一套可靠且灵活的代码和分支管理准则。在机票主流程前端一周多次发版的背景下,对工程高效率迭代和持续集成的需求尤为迫切。不同研发团队在分支管理上有很多优秀的实践,更多的时候会根据团队以及项目特点选择最合适的分支管理策略。
Git分支管理策略其实就是通常意义上的Workflow,目前使用度最高的Workflow前三分别是Git Flow、GitHub Flow、GitLab Flow。基于机票主流程前端团队组成和项目特点等因素上的考虑,我们选择了GitLab Flow,本文将介绍机票主流程前端在GitLab Flow分支管理策略上的实践及演进。
二、分支管理的必要性
随着承接产品线的增加,发布的生产安全问题无时不刻都会存在,对代码的集成便有了更加精益的管理方式,比如对集成分支的保护、借助Merge Request的方式集成代码、建立Code Review规范等。在研发过程中借助分支管理上的一些经验和实践,以尽量减少和避免生产问题。
先说明下机票前端采用Fork仓库的开发方式。Fork服务于一个项目,经常使用在开源场景,当发现原项目存在bug或者有优化空间,可以把原项目Fork下来,相当于拥有一份原项目的备份,可以帮助作继续完善项目或者自行维护一个属于我们自己的项目。当修改完善之后,可以尝试发起Merge Request到原项目,在作者同意本次提交内容后上传的修改则被共享。
正是基于此理念,原仓库及分支被共享,同时借助了Merge Request的代码提交方式,保证了对原仓库每次高质量的代码提交,针对每次提交严格执行Code Review,杜绝向原仓库直接Push代码,对原仓库分支做严格保护。
三、几种分支管理策略
因研发团队成长和项目自身的特点,机票前端经历三种分支管理策略的演变,这三种分支策略在下文分别称之为单分支策略、多分支策略、正在使用的Light Merge分支策略。
在项目起初时,项目主要由固定团队开发和维护,研发工作相对单一,采用单分支策略。
为更敏捷的响应业务的变化和需求侧的多样,项目不再是由固定团队维护,反之由多个小团队单元参与迭代,同一项目在多个小团队单元之间共享,发布周期也较之前大幅缩短。这对团队协作和研发质量有更高的要求,在平时开发工作中采用多分支策略以隔离测试环境和生产环境,同时为了满足多个需求的并行开发引入功能分支开发方式。
考虑到多分支策略中不能提前暴露集成错误、多分支在管理上的开销等问题,通过对过去研发活动中的经验总结和流程规范,逐步总结出一套可被遵循的研发方法,由于持续集成的问题亟需解决,基于Light Merge的更加灵活便捷,同时结合CI/CD,于是采用了Light Merge分支策略。
3.1 单分支策略
各产品线都有固定的发布周期,事先约定产品线发布日窗口,在早期根据产品线的迭代周期从主干分支拉出开发集成分支,同一个产品线的所有开发人员均共享同一个开发集成分支。在开发周期结束后,从开发集成分支发起到主干分支的Merge Request,将代码合并到主干分支上进行发布。
优点:
a. 提前集成所有开发功能,提前暴露集成问题。
缺点:
a. 功能未拆分功能分支,单一开发集成分支的开发方式对开发人员有较高的技术要求和维护成本。
b. 任何commit都可能直接污染开发集成分支,开发集成分支的稳定性得不到保证。
由于产品功能的多样性、更多小团队间合作、更短发布周期的要求,更多的需求以独立的功能分支存在,基于功能分支的开发方式在开发团队内逐渐被推行起来。同时在中大型项目中使用单分支管理策略较高的维护成本,为保障主干分支的发布质量,推出了多分支管理策略。
3.2 多分支策略
在某一个发布日窗口,开发人员共享三个主要分支,分别是主干分支、预发布分支、开发集成分支。功能开发以功能分支的形式存在,功能代码必须经过Code Review和测试验收才可合入开发集成分支,类似发布火车模型在开发集成分支上自由装卸功能。在发布日当天开发集成分支上的功能均合入预发布分支进行测试回归验证,预发布分支是一道生产安全屏障。在预发布分支的测试回归结束后合入主干分支,主干分支用于发布生产。
优点:
a. 开发人员在功能分支上开发功能,团队成员各自开发过程互不干扰,也适合跨团队协作。
b. 共享开发集成分支,功能分支可提前规避冲突。
c. 多环境分支隔离发布环境。
缺点:
a. 过晚集成:这导致不能在发布窗口日之前提前暴露集成问题,同时在发布日当天开发和测试资源过于紧张;过晚集成造成的故障导致开发集成分支被污染,故障功能难以拆分和回滚。
b. 各环境分支几乎无差别,会带来额外的维护开销。大部分产品由于功能架构和模块耦合等原因,往往做不到按时发车和灵活装卸的理想火车模型。
多分支策略虽带来发布环境的隔离,但集成晚且集成效率低,另外多环境分支的管理带来额外的维护开销,迫切需要解决这类繁琐的集成问题。
3.3 Light Merge分支策略
1) 什么是Light Merge?
Light Merge(代码集成加速器)是一种Git分支策略,原理是基于基础分支的不同功能分支的组合,快速增删和自动合并各功能分支,以筛选出可用于上线的功能分支集合。Ctrip代码平台已提供的Light Merge工具及使用,给项目的集成和上线提供了一种高效便捷的解决方案。
2) Light Merge运作机制
为了保障原仓库及分支的质量,在GitLab上的原仓库通常都是被保护起来的,不允许在开发中直接向原仓库分支Push代码。但可以通过发起Merge Request的方式向原仓库分支提交代码,这样借助Merge Request可以完成代码质量检测、单元测试等一系列质量校验活动,保证了代码的集成质量。
在实际操作中,借助Merge Request,在不影响各功能分支的情况下,将多个功能分支做自动集成。一旦某个功能分支代码发生变化,Light Merge被立即重新创建重新执行Merge,检查冲突并通知开发人员。
上图中这里的f1、f2、f3三个功能分支集成,其中任何一个分支代码发生变化,Light Merge会重新触发合并。假如在集成生产前,测试后发现f1存在功能问题,我们可以删除f1功能,选择f2、f3功能上线。(若不采用Light Merge管理功能分支,在单分支或者多分支策略时需要将f1功能做revert操作,而不是简易的操作Light Merge面板。下文中有具体场景的举例。)
Light Merge编辑面板:
Light Merge集成面板:
3) Light Merge的优势
传统的多功能分支集成,通常由开发人员完成繁琐的集成操作,这极易发生代码冲突和集成后的功能障碍,集成过程繁琐低效。基于Light Merge的便捷,开发人员可以自由地选择需集成的功能分支,多功能分支自动合并到集成分支,合并冲突时自动告警,其优势明显:
自由选择需集成的功能分支。
高效定位可集成的功能分支的最大集合。
多分支自动Merge。
集成冲突后自动告警。
Light Merge设置简单。
支持 CI/CD。
与 Merge Request 有机结合。
4) Light Merge分支策略
在实际应用中,开发人员的主要精力均聚焦于所在功能分支上,如图中的 Feature A、Feature B,在多个功能一起开发时不会彼此干扰。开发人员在某个功能分支提交Merge Request后,将与其他分支自动集成,并将集成结果反馈给对应开发人员。
优点:
a. 开发人员在功能分支上做功能开发,而不会被其他功能分支代码干扰。
b. 受研发和产品等不可控因素的影响,基于Light Merge自动合并的机制,将集成的结果及时地通知开发人员,提前暴露集成中的问题。
c. 基于友好的Light Merge工具,根据产品线需要,可以自由快捷地选择需要集成的功能分支。
d. 同时能结合Merge Request和CI/CD,自动构建代码质量检测、单元测试、自动化测试等质量较验工作,节约大量研发和测试成本,同时保证了集成质量。
5) 下面分析一个场景实例,以便能更好的理解Light Merge。
场景:Feature A、Feature B、Feature C功能分支按计划上线,但在集成阶段发现A功能存在Bug且无法如期上线,本次发布中仅上线B、C功能。
解决方案:
1)单分支策略或者多分支策略:在对应开发集成分支上revert A功能代码。
2)Light Merge策略:在Light Merge编辑面板中,移除Feture A的分支。
对比以上方案,方案1在开发集成分支revert操作显得复杂(若A功能有多次Merge Request,需操作多次revert,过程繁琐,提交日志中会有不必要revert操作的记录)。方案2则没有该问题,仅需操作面板即可。
但在实际开发过程中,场景往往通常是这样:在开发集成分支上,功能代码的提交顺序依次是A-B-C-A-B-C,并且B、C的提交对A均有修改。
解决方案:
1)单分支策略或者多分支策略:无法直接在开发集成分支上revert A功能代码,需按照提交Merge Request的顺序依次revert C-B-A-C-B-A。这种revert流程复杂,revert直操作开发集成分支存在较大风险,极易出错而引发新的功能障碍。通常会另起一个新的开发集成分支,cherry-pick Feature B、Feature C的提交到新开发集成分支上,使用新的开发集成分支做功能集成。
2)Light Merge策略:在Light Merge编辑面板中,移除Feature A的分支。
接着上述场景,在集成阶段因临时不可抗拒因素,这次Feature A分支只上部分功能。
Light Merge分支策略解决方案:
1)先将Feature A从Light Merge面板中移除,从Base分支拉出Feature A1分支作为A新功能分支,将Feature A1加入Light Merge;然后再cherry-pick需要上线的功能代码合入Feature A1分支。这种方法不仅使完整Feature A功能得到保留,也很容易地将Feature A功能拆解成Feature A1,Feature A1将如期上线。
2)在Feature A分支上revert不需要上线的提交,并非在开发集成分支上操作,隔离对其他Feature分支的影响。
四、机票在Light Merge分支策略上的实践
Ctrip代码平台的Light Merge工具解决了传统开发代码集成中的困扰。但开发人员期望在平时开发工作中尽可能仅关注当前功能开发,代码的集成和部署均由自动化的流程来完成,开发人员可以及时被通知集成结果并解决集成故障,在Light Merge分支策略上定制了集成规范与自动化工具。
在此之前,开发人员在每次新增功能需求开发时,均需人工地完成功能分支和Light Merge集成分支的创建、集成测试发布和排查集成结果等这一系列繁琐低效的活动;在既有条件下,每一次发布前都需人工完成一系列既定质量较验流程,包括代码质量检测、单元测试、UI自动化测试、打包部署等,以保障发布质量。
结合Merge Request、CI/CD及自动化脚本实现,将分支创建、Code Review、质量检测、打包部署等必不可少的研发活动自动化地完成;基于功能分支构建CI/CD,功能提前集成,保证了持续集成在时间和空间上的最大化利用,同时结合内部通信工具实现功能开发集成的闭环。
4.1 自动化分支管理
根据产品线的发布需要及其周期,可动态申请用于功能开发的功能分支和Light Merge分支。同时在不影响其他功能分支的情况下,功能分支被自动加入对应集成的Light Merge分支。
在功能交付周期结束后,功能分支的生命周期基本结束,线上功能分支的累积也带来一系列新问题,例如申请分支名称冲突、分支难以筛选等,过期的功能分支应当被清理。在交付周期结束后,自动定期地进行冗余分支检查和清理,避免废过期分支的累积,使分支管理更加有效。
4.2 CI/CD支持
在项目上线之前,按照传统经验开发人员需要手动完成一系列上线的集成工作,比如项目编译打包、集成测试、部署等,以保证发布的生产安全。但我们期望构建、测试、发布软件能够更加地快捷、频繁且可靠,而不希望这些过程是由人工重复的工作来完成。经验告诉我们,集成的频率越高越好,更频繁的集成意味着更早的发现某些问题,通过持续的集成及时发现和解决代码故障,提高代码质量,减少故障处理成本,避免线上问题造成的重大损失。
基于Merge Request和结合CI/CD,在功能分支开发过程中频繁高效地集成,自动构建自动化任务,包括但不限于代码质量检测、单元测试、自动化测试、版本部署等,第一时间发现集成中的各类问题,如代码质量、单元测试质量等。
4.3 自动化的生产代码合并和版本管理
在发布日自动执行发起Light Merge分支到主干分支的Merge Request,这不再依赖繁琐的人工操作。在发布结束后自动创建版本标签,以便历史回溯。
4.4 内部IM通知提醒
在产品线的每个研发周期中,在功能分支申请和建立、代码Merge Request、构建CI/CD,生产发布等这些关键路径节点上,结合内部消息通信工具,及时反馈各流程的结果及问题,在整个开发周期内形成一个集成闭环,为研发过程保驾护航。
附:功能分支完整生命周期图:在功能的开发周期中,开发人员仅需关注功能开发和集成结果,而不会被其他繁琐的事务干扰。
五、结束语
产品线的高速迭代要求开发团队具备更高效运作机制,开发团队在使用Git分支管理时通常会考虑采用何种分支管理策略,Git分支管理是团队中的一种应对产品线快速变化的能力,在平时研发工作中我们倾向采用更适合团队和项目特点的Git分支管理策略来提高我们的开发效率,并逐步完善整个开发生产线。
基于Light Merge的灵活便捷的分支策略,这对于项目的团队合作和发布管理都有很大好处,同时结合Merge Request、CI/CD和自动化脚本,很大程度上减少分支管理和代码集成的人工成本。
【推荐阅读】
“携程技术”公众号
分享,交流,成长