Trunk Based Development(主干开发)介绍
主干开发是相对GitFlow和Github Flow更贴合CI/CD(持续集成/持续分发)的高效版本控制管理实践,也更贴合Devops团队。
背景
在软件开发的早年期间,GitFlow和GithubFlow被用来在软件开发中做版本控制管理。
- GitFlow工作流中,分为主干分支(
master
)、开发分支(dev
)、特性分支、分布分支、热修分支等,这些分支都是长期存在的,并在需求开发完成/bug修复完成/代码发布等特定时候执行代码的CR(Code Review)和合码工作。且在合并时,由仓库的核心成员或者管理员们把握代码质量。随着项目的扩大,冲突的几率提高,每次代码合码时候的工作量也大大提升,带来了额外的仓库维护成本。Github Flow便随着Github逐渐流行起来。 - Github Flow工作流中,只有一个主干分支(
master
),一些特性分支以及发布时会用到的分布分支。开发者可以自由从主干分支签出特性分支开发、调试,并在需求完成后合入主干分支。一定程度上减少了长期存在分支的维护成本,但同样的,CR依然是项目管理者进行,特性分支合码时代码量依然有可能很大,团队内规范不好的话,也容易导致合码后主干分支不可发布。
主干开发(Trunk Based Development)是一种更敏捷的git工作流,所有的开发者都可以合码到主干分支,结合CI/CD流程,有助于团队快速迭代。
什么是主干开发
主干开发和CI/CD相互依赖相辅相成。
- 进行主干开发才能保证CI/CD,即每天充分多次的集成乃至发布
- CI/CD过程中的快速自动化测试可以保证主干分支的可发布性
在主干开发中每位或者每小组开发者将自己的工作分成小份,然后以每天至少一次的形式从自己的分支合并到主干,由于每次合并代码量不大,CR时间以及CI时间都会缩短。一个典型的主干开发时间轴如下:
在主干开发中,某些情况下需要从主干分支中选出最佳的bug修复合并到对应版本中,但如果每天发布多次,则根本不需要发布分支,可直接从主干中部署。这样做的最大优势在于减少开发线,频繁执行小批量合并,将代码保持最新。从而降低团队的合码成本。
如何实现主干开发
在进行主干开发时,开发者需要了解如何拆解工作为小份,同时,还需要让构建流程保持通过,如果CI失败,开发者需要立即停止当前工作修复问题,无法短期修复时,也要还原相应更改。通常来讲,主干开发有下面这样的特征:
- 仓库里的活跃分支不超过3个
- 分支的合码频率不少于每天1次,即分支的生存周期不超过1天
- 没有代码冻结期或集成期
在实践中,有下面一些tips:
- 小commit,多合码:将每次合码改动限制在少量的commit和较少的代码改动上,保证合码时轻松;主干分支应该有频繁的小批量改动合码
- 最少1天1合码:每天合并或关闭待合并分支,有效减少合码压力,提高增量发布敏捷度
- 同步Code Review:主干分支的每次合码需要保证CR的及时响应,这可以借助一些代码分析工具的辅助
- 全面的自动化测试覆盖:确保有全面的自动化单元测试套件,保证测试通过后再合并代码,这也是保证主干分支可发布的基础
- 构建快速:降低CI成本,构建和测试需要在几分钟内完成
同时也带来两个新概念
- 分支抽象:在主干开发中,合码频率很高,有些大需求可能没有办法在1天内就完成合码,对于未完成的需求,可以在代码中先埋下未使用的新特性,等待需求完成后,再使用埋好的新功能。这种在源代码中提前埋下“代码分支”的方式成为抽象分支(Branch by abstraction)
- 特性开关:在分支抽象的基础上,有些合并到主干的改动不一定想让所有用户都看见,可以在代码中预先埋入分支语句,再从配置中读取当前是否使用特性。这样可以实现功能灵活切换、实现ab-test等效果
标准开发流
1 | git checkout master && git pull --prune |
- 更新本地master分支
- 签出特性分支
- 编码
- 推送本地分支到远端
- 提MR,如果MR后有更新,继续push,当rebase master遇到冲突时,推送需要增加
-f
参数 - 合码
注:因为主干开发每次合码量不大,建议使用
rebase
解决冲突
主干开发的好处
主干开发的最大好处在于对CI的亲和度。可以想象开发者完成当日工作,当日合码,当日测试通过完成集成,达到可发布状态。很大程度减少了合码的痛苦。进而有:
- 持续CI
- 持续CR
- 持续CD
总结
非常适用于敏捷开发中,对于团队成员能力过关(要懂得怎样拆分需求)、测试有着良好建设的团队来讲,是种提效的好方式,值得一试。相反如果成员拆分不够良好、代码review不够及时,测试不够自动化和系统,则不适用主干开发。