【QCon】精华内容上线92%,全面覆盖“人工智能+”的典型案例!>>> 了解详情
写点什么

字节研发设施下的 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:059209

评论

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

Java 踩坑 2|Feign Client 访问到 Consul 脏节点/故障节点

itschenxiang

Java Consul springboot

笔记软件哪个好用?36款好用的笔记软件合集推荐!

彭宏豪95

效率工具 markdown 在线工具 Mac笔记软件 笔记应用

云拨测全面升级丨单次拨测低至 0.001 元

阿里巴巴云原生

阿里云 云原生 可观测

分布式系统中的数据复制

越长大越悲伤

分布式 数据复制

Linux之Cnetos7.6安装Vue.js教程。

百度搜索:蓝易云

vue.js 云计算 Linux centos 运维

解决直播间源码音视频不同步问题的有效方式——山东布谷科技创作

山东布谷科技

软件开发 实时音视频 源码搭建 直播源码 直播间

shardingsphere配置读写分离集群(1主2从结构)

zhengzai7

读写分离 ShadingSphere

《Programming Abstractions In C》阅读笔记p69-p71

codists

【活动】30 秒上云体验,一键体验 RocketMQ 六大生产环境

阿里巴巴云原生

阿里云 云原生 Apache RocketMQ

Nautlius Chain主网正式上线,模块Layer3时代正式开启

大瞿科技

Mediabox:年度最佳音视频开发工具

阿里云视频云

云计算 阿里云 音视频 视频云

人工智能革命|是疯狂炒作还是大势所趋?

SEAL安全

B2C #人工智能 ChatGPT 企业号 7 月 PK 榜 趋势解读

一文读懂Hhybrid App开发模式

没有用户名丶

Ubuntu 20.04系统编译安装Apache教程。

百度搜索:蓝易云

Apache 云计算 Linux ubuntu 运维

实施Scrum敏捷开发必选的敏捷工具

顿顿顿

Scrum 敏捷开发 项目管理工具 Scrum Master 敏捷开发管理工具

2023-07-18:给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空), 使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度,如果

福大大架构师每日一题

福大大架构师每日一题

大模型基础学习

天天向上

Ubuntu 20.04系统编译安装Nginx1.22教程。

百度搜索:蓝易云

nginx 云计算 Linux ubuntu 运维

B站&华为云 | 融合虚实宇宙,开启云上视听的黄金时代

白洞计划

AI B站

GreatSQL通过错误日志信息判断数据库实例是如何关闭的

GreatSQL

数据库 greatsql

数字化转型与架构-规划篇|承上启下的能力热力图

数字随行

数字化转型

LCD拼接屏、LED显示屏和OLED显示屏的主要区别

Dylan

LCD1602液晶显示屏 LED显示屏 led显示屏厂家 OLED

代码随想录 Day21 - 二叉树(七)

jjn0703

从零开始实现Go搜索引擎(一)

geange

搜索引擎 lucene #数据库 FST #go

如何处理需求池?管理需求池的内容

Bonaparte

产品 产品设计 产品思维 产品需求

C语言如何实现DES加密与解密

攻城狮Wayne

快照隔离级别原理 | StoneDB 技术分享 #1

StoneDB

MySQL 数据库 HTAP StoneDB

时序数据库 TDengine 与金山云两大产品完成兼容互认证

爱倒腾的程序员

数据库

Linux搭建我的世界MC服务器 - MCSM面板教程。

百度搜索:蓝易云

云计算 Linux 运维 Minecraft MCSM

机器学习之PyTorch和Scikit-Learn第3章 使用Scikit-Learn的机器学习分类器之旅Part 2

Alan

人工智能 机器学习 PyTorch scikit-learn

演讲实录:以 AI 变革组织运营与管理

Kyligence

数据分析 数智化 企业级OLAP

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