作者简介
苏玲,5年软件配置管理及7年持续集成经历。曾在苏州科达科技和大众点评任资深配置管理工程师,目前为携程代码中心负责人,专注于代码相关的平台建设,致力于提高研发效率与研发质量。
李海涛,目前为携程代码中心高级研发工程师,负责实现了Gitlab sharding和hybrid的代码评审服务。
一、综述
携程从2013年开始引入了Gerrit和Gitlab两款代码评审服务,开发团队可自行选择其一用来管理代码。
其中,Gitlab开源项目经过四年的发展,持续优化了代码管理相关功能,还提供了很多DevOps的增值服务。而Gerrit提供的pre-commit的方式,也有其优势。
为了代码平台统一,携程代码中心团队在Gitlab上提供了类Gerrit的代码评审方式,推出了既有change@Gerrit方式又有merge request@Gitlab方式的hybrid的代码评审服务。
本文先分析两种review方式的优点,然后通过介绍几个场景来指出Gitlab中增加change功能的必要性,以及如何把hybrid的服务用到极致,并归纳出几类代码评审模式分别适合的场景,希望对开发团队有所帮助。
二、简称
本地开发每个commit都自动产生一个change,没经过review的变更不能进入公共的Git仓库,这种方式我们简称为CHANGE 。
每次review都要提交两个分支进行合并的Merge Request,这种方式简称为MR 。
三、Gerrit与Gitlab的PK
我们只比较两个平台在代码评审上的差异,然后提炼出优点。
Gerrit提供了pre-commit的评审方式,通俗地说,就是没经过review的变更是不会进入到Git仓库里面。而Gitlab没有pre-commit的功能,只提供了post-commit的功能,也就是在同一个Git仓库中,任何开发人员必须向Git仓库推送自己的分支,然后发起Merge Request后才能请别人帮忙review代码。
Mr. Gitlab :你不想正式的仓库被坏代码弄脏,那你用Gitlab fork的方式好了,只要不接受Merge Request,脏的代码只会存在fork出来的仓库里面,正式的仓库一样可以实现pre-commit的功能。
Mr. Gitlab:我们团队采用的是特性分支开发的分支模型,需求管理系统中新增一个需求就会自动创建一个分支,每个分支名就能看出特定的一个功能点,这个多好,想知道一个迭代周期有多少个功能要交付,看看有多少分支就行了,而且这些新建的分支就像计划任务一样提醒着开发人员。代码评审就用Merge Request,当特性分支开发完毕,发个Merge Requst到master分支就行。
Mr. Gerrit:Gerrit也可以为每个特性分支创建分支的,还能为特性分支上的每个commit建立review申请。另外,你们每次做review,都得打开Gitlab的页面,手工发起一个Merge Request,这个太麻烦了,大家看看Gerrit的做法吧,开发人员只要在自己的开发设备中,push一个特殊的变更,Gerrit上就能自动创建一个change了,根本不用人再登到Gerrit系统上去申请review。
Mr. Gitlab:我不喜欢Gerrit对每个commit 单独地做review,用MR多好,一个分支合入另一个分支做个review,这样虽然一次性review多一点,但不用在多个changes中跳来跳去,而且分支是可以多人共享的,我一次性可以review多个人的变更。
Mr. Gerrit:我觉得对单个commit做review挺好的,一个功能一个commit,这样更容易发现问题。
Mr. Gerrit:CHANGE的方式,很容易创建出linear history的分支,这样便于用bisect定位问题的出处。MR行不行呢?
Mr. Gitlab:MR当然也可以,虽然是两个分支之间发起merge request,但是项目策略配置为Fast-forward merge就行啦。 ”
看了上面的讨论,我们发现有些所谓的“优点“并不明显,需要在特定场景下才拥有,有些优点则很明显。我们用表格形式做个归纳:
具体优点 | 是/否优点 | Gerrit具备 | Gitlab具备 | PK结论 |
---|---|---|---|---|
未经review的代码不会进到Git仓库 | 是 | 是 | 是(但要fork仓库,管理成本增加) | Gerrit 胜出 |
Push的时候自动发起了review的申请 | 是 | 是 | 否 | Gerrit 胜出 |
Review一个分支,而不用review每个commit | 是@某些情况 | 否 | 是 | Gitlab 胜出 |
Review单个commit,保证review的质量 | 是@某些情况 | 是 | 否 | Gerrit 胜出 |
能实现linear history | 是 | 是 | 是 | 打平 |
上面PK的内容没有涉及review功能的所有特性,也不是用来说明Gitlab的review不如Gerrit的,而是告诉大家,某些情况下团队确实需要Gerrit的这种pre-commit的方式。我们不妨继续探讨一下,哪些情况下适合用CHANGE 。
四、特别适合用CHANGE的场景
场景1:主干分支开发的项目。
因为所有的变更都要求在第一时间提交到唯一的开发分支上,保持持续的集成,如此一来,特性分支就没必要存在了。这种情况下,用CHANGE最适合。
开发在本地始终基于主干分支做开发,开发完毕,直接向远端的refs/for/主干分支push即可。一提交,远端自动创建一个change,该change通过review后,其对应的commit就合入到主干分支;如果review没被通过,则变更的内容就不会进入到主干分支。
场景2:特别重视代码质量的团队。
此类团队不允许质量低劣的commit存在仓库中,也不想用fork的方式,因为fork的方式不够简洁和直接,fork出去的仓库需要经常fetch原仓库,需要维护多个remote 。
场景3:有较多开发新手的团队。
新手提交的变更先经过review然后才能进入到Git仓库。
五、CHANGE和MR同时使用的场景
给Gitlab引入CHANGE,很自然地会想起一些问题“难道仅仅是为了让Gerrit顺利下线,我们才把CHANGE引入到gitlab吗?”或者“现有采用Gitlab MR的团队是否也能享受CHANGE带来的好处呢?”
静下来想一想,还真的存在下面的场景,如果同时使用CHANGE和MR,可以有效提高代码评审的效果。
团队特征:
- 采用特性分支开发模式,每个功能对应一个分支。
- 特性分支开发完毕,合入master分支后发布。
- 有不少开发的新手。
开发流程:
- 甲、乙、丙三人同时负责A功能的研发,共同分享feature-A分支。
- 甲负责review乙、丙的代码。
- Feature-A分支设为保护分支,变更前需review代码。
- 乙和丙在本地基于Feature-A开发,自测完成后push到refs/for/Feature-A。
- 甲在gitlab上review后,乙、丙的变更被合入到Feature-A 。
- 然后甲向master发起了一个Merge Request。
- 由上一级集成人员review后,最终Feature-A被合入到了master 。
“CHANGE和MR同时使用”,比起 “只使用MR”,优点很明显:
以前只有MR的情况下,如果甲要review乙和丙的代码,除了结对编程外,还有一种方式,把Feature-A保护起来,不允许直接push,然后,甲和乙基于Feature-A创建新的分支,开发完成后再Feature-A向发起MR 。而“CHANGE和MR同时使用”,可以省掉额外新建分支的麻烦,且省掉了发起MR的麻烦。
我们不妨用下面的简图呈现CHANGE和MR的关系:
如此一来,在不增加远端仓库分支的情况下,基层review人员依赖CHANGE,保证每个commit的代码质量,从而确保特性分支的质量;另一方面,主干分支的集成人员借助MR,无需在个人环境上做分支的集成,待review人员完成评审后,他们就能一次性地在Gitlab界面上把特性分支合入到主干分支,从而保证master主干分支能被高效地集成。
六、Hybrid代码评审服务的模样
1)尽可能保留Gerrit本地操作的方式:
git push origin HEAD:refs/for/目标分支 。
2)项目首页,提供CHANGE的clone方式:
3)CHANGE和MR并存:
七、代码评审模式的类型与适用场景
MR和CHANGE都提供代码评审的功能,并且携程Gitlab平台同时支持这两种功能。非常自然地,大家极有可能会问:“什么时候该用MR,什么时候用CHANGE,什么时候同时使用,什么时候可以都不用呢?”
我们用下表做个归纳:
序号 | 模式 | 适合的场景 |
---|---|---|
1 | CHANGE | 同时满足以下几个条件:产品有质量要求。主干开发主干发布。 |
2 | CHANGE MR | 同时满足以下几个条件:产品有质量要求。非“主干开发主干发布”。不少能力较弱的开发人员。 |
3 | MR | 同时满足以下几个条件:产品有质量要求。非“主干开发主干发布”。很少能力较弱的开发人员。 |
4 | 无代码评审 | 对质量没什么要求的项目。或者每个成员都是神一样的人,永远交付高质量的代码。 |
- 产品有质量要求。
- 主干开发主干发布。
2CHANGE MR同时满足以下几个条件:
- 产品有质量要求。
- 非“主干开发主干发布”。
- 不少能力较弱的开发人员。
3MR同时满足以下几个条件:
- 产品有质量要求。
- 非“主干开发主干发布”。
- 很少能力较弱的开发人员。
4无代码评审
- 对质量没什么要求的项目。或者
- 每个成员都是神一样的人,永远交付高质量的代码。
结合上面的分析与归纳,大家不难发现:这套既有CHANGE又有MR的hybrid的代码评审服务,为那些分支策略多样性的公司的代码评审提供了灵活性和高效性。
作为一款代码评审服务,它不仅仅适合携程,同样也适合与携程有类似特征的公司。
八、结束语
hybrid代码评审服务的推出,预示着携程即将全面下线Gerrit,统一代码平台为Gitlab,期待携程的研发能从中获益,从而进一步提高review效率。
我们也希望hybrid的方式,能给代码平台的建设提供一种新的思路。当崭新的事物出现的时候,我们不妨听听用户的心声,看看如何能把旧事物里面好的一些设计理念有机地结合到新事物中。如果hybrid得非常巧妙的话,很可能会有非常棒的效果。