hello云胜

技术与生活

0%

trunk-based开发管理模型实践

目前业界主流的版本管理流程是Gitflow 和 trunk-based。

Gitflow流行的比较早。但是目前的流行度要低于 trunk-based模式工作流。trunk-based模式被誉为是现代化持续结成的最佳实践。

他俩的核心区别是,Gitflow是一个更严格的流程,只需要特性的管理员来批准代码可以合入主干。这样可以保证主干分支的代码质量。

而trunk-based流程相对而言更开放,所有开发者都有权限合入主干,以此来达到团队快速迭代功能的目标。

trunk-based流程

img

  1. 所有研发人员直接在trunk上提交代码

  2. 对外发布产品的时候需要从trunk上拉取release分支(比如1.1.x和1.2.x),并基于release分支来发布(比如1.1.0和1.1.1)

  3. release分支中出现的bug或者需要性能优化时,则需要在trunk上完成,并通过cherry-pick的方式在trunk中挑选对应的commits合并到release分支,此时的小版本号从1.1.0变成1.1.1

  4. 对外发布新功能时,需要基于trunk分支,重新拉取release分支,版本号从1.1.x变成1.2.x,同时1.1.x的release分支将被废弃

  5. trunk分支上,每个commit之间的提交间隔很短,通常在一天之内提交好几次,甚至更多次

trunk-based vs. Gitflow

Trunk-based流程的特点在于其名字,基于主干进行开发。

鼓励(或者说要求)开发者应频繁的将小的改动及早的合入主干分支。

这样开发者会创建短命的分支,而不是创建生命很长的特性分支。

Trunk-based是现代DevOps生命周期的常用实践。实际上Trunk-based是CI/CD的必备实践。

随着代码库复杂性和团队规模的增加,Trunk-based模式会比Gitflow流程显著降低代码冲突,而保证生产版本的顺利迭代。

Gitflow工作流基于master主干分支和develop开发分支,这俩个长期分支。

以及hotfixes, features, 和releases三个不同功能的临时性功能分支。

这三个分支根据其角色不同,又会有不同的合并策略。

Trunk-based流程相比于gitflow流程更加简单,没有那么多不同的分支需要管理。开发和发版都基于主干进行。

在Trunk-based流程下,主干分支应该始终保持稳定,没有问题,随时可以进行部署。

而这也是cicd的必备条件。

trunk-based流程的优点

  1. trunk-based流程是实现持续集成的必要条件。我们已经搭建好了自动化的部署和测试流程,但是我们的开发还是使用相互独立的分支,合并代码也是开发完一个大功能才进行合并,那么就很难发挥持续集成的优势。

    trunk-based流程中所有人基于main主干开发。我们在main主干上配置自动化的部署和测试和代码检查工具。

  2. trunk-based流程可以有助于降低代码合并时的冲突。因为trunk-based流程要求高频次小规模的提交,所以即使冲突,解决起来的难度也比较低。

  3. trunk-based流程要求高频次小规模的提交,使代码review更加高效和靠谱。

  4. 开发团队应该每天都提交合并代码。并且要始终保证主干代码的状态的绿的。也就是说主干始终都是可用的,随时可以进行部署交付的。

最佳实践

小规模高频次的开发任务

trunk-based流程注重快速的迭代节奏。保持较小的提交和分支可以更快地进行合并和部署。

只有几行代码的小改动更有利于减少代码审核人员的认知压力。

所以我们应该将任务划分成许多可以在1天以内完成的小模块

Feature flag功能标签

Feature flag的作用就是让开发者可以将开发的代码先提交,但是不启用。等以后再启用。

这样做的目的是可以避免创建新的特性分支,而是直接在main主干上开发新功能。

这样说有点抽象,举个例子

Feature flag是一个代码开发上的手段,说直白了就是代码中嵌入特性开关这种判断。

比如这种js代码

1
2
3
if(featureFlags[‘new-cool-feature’] == true){
renderNewCoolFeature();
}

通过这种开关,即使我们的功能没有完全开发完成,也可以先进行提交,只要能保证通过编译部署。

还可以通过Feature flag实现灰度等功能

![Feature Flagging Diagram - Desktop](D:\github\docs\git\trunk-based开发管理模型.assets\Feature Flagging Diagram - Desktop.png)

全面的自动化测试

自动化测试也是现代化CICD不可或缺的组成部分。

团队中的每一名开发都应该针对自己的功能模块来编写对应的单元测试,并在开发结束之后,在本地运行这些单元测试来验证代码的功能。

在开始开发新功能是,从主干拉取代码到本地后,首先要执行单元测试,已确认基础代码是ok的。

单元测试的原则是每一个单元测试能够独立运行并且能够在短时间内(5分钟)运行结束

及时的代码review

代码review放在自动化测试和自动化代码检查之后,因为已经通过了test和code coverage。reviewer只需要关注代码的功能和性能方向。所以同事进行review所需的时间不会很长。

这可以保证及时完成代码review,然后将代码尽早合入主干

每天至少合并主干一次

研发人员可以直接在trunkmaster分支上提交代码,当然也可以拉取feature分支,但是feature分支的生命周期应该在1天之内

分支数量不应该超过3个

分支数量不应该超过3个的说法可以讨论,底线是不应该超过这个代码仓库下开发人员的人数。

比如这个项目有5个开发,那么最大程度上,每人拉取一个feature分支。

进行了分支代码merge之后,最佳实践是删除无用的分支。

高效的CI服务

因为每一个提交到trunk上的改动,都会自动地触发CI服务。所以必须保证ci服务高效执行,能够快速完成构建和测试。

主干的可用性为第一要务

如果提交的代码不小心破坏了主干代码。必须立即停下手头的工作。优先修复主干问题。

如果这个问题无法快速解决,那么需要将此次提交撤销,并回退到上一次提交。这么做就是要确保trunk分支随时可用。

总之

Trunk-Based 流程更多的是依赖于人的行为,需要团队中的每一名成员都要掌握流程规范。

然后在一致的行为下应用自动化工具才能够从整体上提高企业的研发效率