阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

字节研发设施下的 Git 工作流

  • 2020-10-30
  • 本文字数:4293 字

    阅读完需:约 14 分钟

字节研发设施下的 Git 工作流

Git 提供了丰富的分支策略和工作流方式,我们在深入学习业界 Git 工作流时,每种工作流都设计的非常好,似乎都能运用到团队实践。但在引入 Git 工作流规范开发时要留意:Git 工作流仅仅是整个研发流程中的一环。上游项目管理/缺陷追踪系统虎视眈眈,下游 CD (Continuous Delivery) 嗷嗷待哺,还得考虑团队规模、产品形态、发版方式等等因素。因此,在团队中落地 Git 工作流规范并不是一件能轻松决定的事。

字节跳动 Git 仓库有效的 CR (Code Review) 覆盖率 70%,仍有提升空间,通过调研,团队中又以 GitHub Flow 模式居多。随着字节研发效能建设愈发完善,GitHub Flow 已无法充分利用研发设施进行提效并保障工程质量,很多团队均意识到这点并着手建设流程规范。

本文通过介绍业界 Git 工作流和公司研发设施现状,力求从仓库形态、部署流程等多角度进行分析,给出一些制定工作流规范的建议。

业界 Git 工作流介绍

Git Flow


图片来源:


初级 Git 开发者,面对这满图的分支和 merge 指向,简直想手撕作者。高级 Git 开发者要将这个流程运用实践也大感头疼。


Git Flow 有不少优点:


  • 分支各司其职,覆盖大部分开发场景。

  • 预期 master 分支中任何 commit 都是可部署的。

  • 严格按照流程执行,出现重大事故的情形会大大降低。


缺点也不少:


  • 过于繁琐,无法要求所有团队成员按照这个流程严格执行。

  • 违反 git 提倡的 short-lived 分支原则。

  • master 分支历史记录并不干净,只能通过打 Tag 标记哪些是 master 真正要部署的。

  • 对持续部署和 monorepo 仓库不友好。

GitHub Flow

GitHub Flow 是一个基于分支的轻量级工作流。它突出了 CR 的重要性,有助于我们掌握 CR 的开发模式,但它没有解答部署、环境、发布、集成等问题。



图片来源:

GitLab Flow

GitLab Flow 并不像 Git Flow, GitHub Flow 一样具有明显的规范,它更多是在 GitHub Flow 基础上,综合考虑环境部署、项目管理等问题而得出的一种实践。

基于环境:



图片来源:

基于发布计划:


图片来源:

Trunk-based Flow

和“基于发布计划”的 GitLab Flow 类似,有一个主干分支接受所有开发者的 commit,并为后续 CI/CD 提供关键助力。


按照官方文档描述:「你可以选择直接向主干分支提交代码的方式(适用于小团队)或者采用 Pull-Request 的方式,只要保证特性分支不能长期存在,并且产品是独立存在的。(the product of a single person.)」,trunk 分支提交是比较随意的(不一定可部署),但也需要走 CR,可以采用 Fast-forward 形式的 merge 保证主干是一条线,到了合适的时间点,checkout release-* 分支,执行正式上线操作。


一旦发现 release 分支有 hotfix 需求,则先在 trunk 分支上进行 fix 开发,测试完成后,cherry-pick 到 release-_ 分支,确保修复代码即在 release-_ 中上线,又能被下一个 release 周期包含。



图片来源:

Aone Flow

按阿里云开发者社区描述:Aone Flow「基础玩法是将每条发布分支与具体的环境相对应,比如 release/test 分支对应部署测试环境,release/prod 分支对应线上正式环境」,这种发布方式可保证每个 feature 都被测试,但不能保证 release/test CI 通过的 feature,能在 release/prod 环境也通过(feature pick 组合不同)。


「进阶点的玩法是将一个发布分支对应多个环境,比如把灰度发布和正式发布串在一起,中间加上人工验收的步骤」。实质是将基础玩法中的“release/test”,“release/prod” 改成 “release/combine-feature”,固定了 feature pick 组合,保证 features 在各个环境测试的一致性。


Aone Flow 的 pick 模式,适合复杂仓库大团队持续上线,避免了 Trunk-based Flow 引入未完成 feature 的问题。但似乎不适合周期发版的要求。一个发版周期内会创建多个 feature ,上一个发版周期可能遗留若干 feature,随着时间推移,feature 数越来越多,最终发版人在 pick feature 过程中疯掉。



图片来源:

公司实践

字节跳动的 Web 服务都跑在私有云 CE (Compute Engine) 中,部署产物则由统一的代码编译发布和版本管理平台分发,每个构建产物都有一个 AR (Artifact Repository) 管理。

多环境部署现状

服务端视角

服务端微服务跑在 CE 上,代码编译由 AR 完成,CE 和 AR 是 1:N 的关系,一个应用的运行依赖多个 AR,在进行环境管理时,需要以 CE 为纬度来区分。从 CE 视角来看,公司有 5 类环境(以国内产品为例):



通过 headers -H 'x-env-tag:{env}' 将流量导向不同环境,满足“开发测试”、“QA 测试”、“预发测试”、“小流量测试”、“全量上线” 各阶段的测试需求。


CE 测试环境服务示例:


前端视角

前端和服务端有差异,一个 URL path 访问的资源通常由一个 AR 产出,URL paths 和 AR 是 N:1 关系,所以前端部署以 AR 版本来区分环境:



前端部署可为测试环境和产品预览环境生成独立的域名进行测试,也可通过设定 headers -H 'x-env-tag:{env}' 进行环境导流。

团队实践的 Git 工作流

结合前后端的环境现状,可整理三类研发流程:


  1. 功能测试流程(测试环境)

  2. QA 提测流程(测试环境)

  3. 上线发布流程(测试、预发、灰度、线上环境)


公司内目前有三种 Git 工作流与之对应:


  • 小步快跑:单主干



  • 周期发版:双主干



  • 周期发版:三主干



对比“双主干”和“单主干”,


有联系


  1. 处于 MR 状态的迭代分支 ≈≈ 研发主干 Dev

  2. 单主干 Master ≈≈ 发布主干 Master


也有区别


  1. 单主干的“研发分支”不存在一个固定的测试环境(相较于双主干 dev 分支)

  2. 多个 feature 同时发测试环境时需要组合成新分支,管理不便

  3. 单主干迭代分支在 MR /非 MR 状态下的 CI 流水线有差异

单主干实践

前端微服务管理平台

字节前端微服务平台属于成熟业务,只需做少量 feature/fix 开发,在工作流上采用单主干模式。



本地测试后,不再经过功能测试环境测试。发起 Merge Request,CR 通过合码后,上测试基准环境进行测试,如发现问题,回滚,进入下一轮 CR。


虽然小修小改影响风险小,但流程缺乏进入功能测试环境的流程,还是存在隐患,有可能影响测试环境的业务方使用,不是很好的实践。


单主干只适应于业务规模小,成熟度高无大改动的项目。但无论业务规模如何,执行上线发布流程前,都必须先经过线下环境验证。

双主干实践

私有云平台

云平台的 Git 工作流是由繁入简的过程。最开始为每个部署环境设定了一个部署分支。feature 分支的 commit 点需要和三个环境的部署分支发生 merge,起不到串联测试的目的。



经过改进后,采用标准的 Trunk-based Flow,仍能满足 online/sandbox/boe 三个环境的部署要求。



云平台参与业务方有上百个(类似阿里云平台),虽然图中仅展示了三个环境,但实际上 5 大环境的使用都融入了日常开发中。

某业务中台

某业务中台的 Git 工作流重点阐述了同一个项目多人协作开发时会遇到的问题:


  1. 多个 feature 各自独立提测, 临近上线合码时有较多冲突, 可能导致线上 bug

  2. 提测前和提测中, 如果 master 更新了, 可能没有及时同步下来, 上线前合入 master 可能会导致冲突或 bug

  3. 在流程设计上,master 作为发布分支,release-* 为提测分支,结合了单主干的便捷(hotfix 直接和 master 交互)和双主干对 feature 的管理

  4. 和 Trunk-based Flow 刚好相反,主分支是发布分支,提测分支是短期的

  5. 另一个比较有特点的是,在 release 测试过程中,发现某个 feature 的 bug, 直接从 release 分支 checkout 出来进行修复,并再次合入 release


Jupiter 工作流规范

Jupiter 是字节 Web 开发引擎,覆盖 Web、组件库、BFF、SSR 等前端开发领域。Jupiter 推荐 Trunk-based Flow 类似的 Flow,并从 CI/CD 角度出发,在开发新需求、hotfix 等时机给出 Git 操作建议。


  1. 有重叠人员参与的各项目之间有一致的流程和模式,避免增加认知负担,避免同一个人在不同项目之间切换时混淆和迷惑,也能集中力量做实践和改进,共享经验和基础建设。

  2. 上线节奏要灵活。既照顾早期的项目,也照顾规模化落地的项目,考虑到项目在追求不同里程碑时,上线频率会有变化。所以每周上线一次、每天上线一次(适合人多、稳定性要求高的项目)、一天内分多次上线多个 feature,都有可能,不能限定一个固定的节奏。任何人,在任何时候都可以发起上线。

  3. 支持 monorepo。不同方向不同人参与的项目,可能会共用一个仓库,方便复用代码和基础设施。所以仓库中不同项目可能有不一样的上线节奏和上线需求。

  4. 鼓励持续集成(CI),集成不等同于部署,发 MR 集成代码的时候不用有压力,不会在不知情的情况下被上线。也鼓励持续部署(CD),部署不等于发布,不能发布的代码,在正式上线前有机会关掉。

  5. 上线过程必须是固定、重复、能统一改进,能逐步增加自动化的,不能每次上线时重新、临时规划或修改上线方法,增加负担和成本。

  6. CI 是 CD 的前提,没经过 CI 的修改不能进入 CD 环节。

  7. 不能有任何修改不经过 staging(预发布,尽可能跟线上一致)测试,直接上线。

  8. CI 和 CD 的历史记录要绝对可靠、可追溯,只能增加,不能减少和修改。

  9. 尽可能减少手动操作环节,避免在特定的个人机器上做上线操作。

三主干实践

亿级 App

App 发版应该是目前为止最为复杂的分支管理场景了。客户端安装包一旦下发到渠道被用户下载,如果无法通过热更新修复,将严重影响 App 用户留存。App 发版具有更规范的发版规律,Feature Toggle 必不可少,当我们觉得 CR,CI/CD 麻烦时,对比开发上线一个影响上亿用户的 App feature,是不是感觉做 Web 的 CI/CD 简单多了?


总结

本文尽可能从多角度阐述 Git 工作流的使用姿势,希望对大家有帮助。Git 工作流是为了上线有保障,上线过程中充分测试必不可少,良好的 Git 工作流能保障测试是渐进且可靠的。环境管理和 Git 工作流结合在头条内部也形成了很多规范,包括「环境部署」、「流量调度」、「连通性测试」等使用规范;「限定场景允许」、「暂时场景允许」、「限定流程允许」等环境约束规范。再结合 CI/CD,我们就可以全链路保障业务的快速迭代、安全上线。

参考资料

  1. Trunk-based Development vs. Git Flow

  2. ( https://www.toptal.com/software/trunk-based-development-git-flow )

  3. Please stop recommending Git Flow!

  4. ( https://georgestocker.com/2020/03/04/please-stop-recommending-git-flow/ )

  5. Understanding the GitHub flow

  6. ( https://guides.github.com/introduction/flow/index.html )

  7. Introduction to GitLab Flow

  8. ( https://docs.gitlab.com/ee/topics/gitlab_flow.html )

  9. https://cn.trunkbaseddevelopment.com

  10. 在阿里,我们如何管理代码分支?

  11. ( https://developer.aliyun.com/article/573549 )

  12. 谷歌的代码管理

  13. ( http://www.ruanyifeng.com/blog/2016/07/google-monolithic-source-repository.html )


本文转载自公众号字节前端 ByteFE(ID:ByteFE)。


原文链接


字节研发设施下的 Git 工作流


2020-10-30 14:059267

评论

发布
暂无评论
发现更多内容

APISIX Ingress 如何使用 Cert Manager 管理证书

API7.ai 技术团队

证书 api 网关 APISIX Ingress Controller

单线程 Redis 如此之快的 4 个原因

C++后台开发

redis 中间件 后端开发 单线程 C++开发

如何用Apipost校验响应结果

爱研究代码的极客人

APi设计 JSON Schema apipost

聊聊Docker镜像

天翼云开发者社区

Docker 镜像

工业生产环境下,时序数据库 TDengine 如何打造全面有效的数字化监控?

TDengine

数据库 tdengine 时序数据库

使用Jira盗版会存在的6大风险

PingCode

项目管理 软件开发 软件管理

泰山众筹sun4.0矩阵合约系统开发搭建

开发微hkkf5566

OpenHarmony标准系统内核学习【2】CPU轻量级隔离特性

离北况归

OpenHarmony

LeaRun快速开发平台:自由搭建个性化门户

力软低代码开发平台

全景剖析阿里云容器网络数据链路(三):Terway ENIIP

阿里巴巴云原生

阿里云 云原生 云原生容器

浪潮云:以数据云IBP释放数据要素力量

浪潮云

云计算 数据云

MySQL中的distinct和group by哪个效率更高?

Steven

统一观测丨如何使用 Prometheus 监控 MySQL

阿里巴巴云原生

MySQL 阿里云 云原生 #Prometheus

行云洞见|为何行业权威都预测“云原生IDE 将成为常态”?

行云创新

ide 云原生 云端IDE Cloud IDE TitanIDE

单线程架构的Redis如此之快的 4 个原因

JAVA旭阳

redis 缓存

全球化安全生产 & 质量保障体系建设探索

阿里技术

质量保障 安全生产 全球化技术能力

订单流量录制与回放探索实践

得物技术

Java 运维 后端 稳定生产

理论+实践,教你如何使用Nginx实现限流

华为云开发者联盟

后端 开发 华为云 企业号 2 月 PK 榜 华为云开发者联盟

线上网络丢包引起的接口响应时间过慢,快速排查案例

KINDLING

Java 运维 网络 丢包 eBPF&Linux

SparK 用稀疏掩码为卷积设计 Bert 预训练

Zilliz

计算机视觉

易观千帆 | 12月用户体验GX评测:国有行及股份行持续领跑,农信社用户体验关注提升

易观分析

金融 手机银行

简单概述Serverless

天翼云开发者社区

10大知识管理软件厂商有对比

PingCode

项目管理 知识管理软件

谈谈我工作中的23个设计模式

阿里巴巴中间件

阿里云 云原生

新年新气象,老兵开新坑

致知Fighting

Java Go 服务器

RocketMQ Streams拓扑构建与数据处理过程

Apache RocketMQ

RocketMQ 消息列队

一文教你如何重新认识用户

蔡农曰

互联网 产品经理 消费者 需求设计

智能合约佛萨奇系统开发,佛萨奇2.0源码搭建

薇電13242772558

基于GIS+WebGL智慧消防3D可视化云控系统

2D3D前端可视化开发

智慧消防 消防物联网云平台 消防三维可视化 智慧消防系统 消防云控平台

如何通过jstat命令进行查看堆内存使用情况

华为云开发者联盟

后端 开发 华为云 企业号 2 月 PK 榜 华为云开发者联盟

NFTScan 正式上线 Fantom 网络 NFTScan 浏览器和 NFT API 数据服务

NFT Research

NFT 数据基础设施

字节研发设施下的 Git 工作流_软件工程_字节跳动技术团队_InfoQ精选文章