技术编程|字节研发设施下的 Git 工作流


Git 提供了丰富的分支策略和工作流方式 , 我们在深入学习业界 Git 工作流时 , 每种工作流都设计的非常好 , 似乎都能运用到团队实践 。 但在引入 Git 工作流规范开发时要留意:Git 工作流仅仅是整个研发流程中的一环 。 上游项目管理/缺陷追踪系统虎视眈眈 , 下游 CD (Continuous Delivery) 嗷嗷待哺 , 还得考虑团队规模、产品形态、发版方式等等因素 。 因此 , 在团队中落地 Git 工作流规范并不是一件能轻松决定的事 。
字节跳动 Git 仓库有效的 CR (Code Review) 覆盖率 70% , 仍有提升空间 , 通过调研 , 团队中又以 GitHub Flow 模式居多 。 随着字节研发效能建设愈发完善 , GitHub Flow 已无法充分利用研发设施进行提效并保障工程质量 , 很多团队均意识到这点并着手建设流程规范 。
本文通过介绍业界 Git 工作流和公司研发设施现状 , 力求从仓库形态、部署流程等多角度进行分析 , 给出一些制定工作流规范的建议 。 业界 Git 工作流介绍Git Flow

技术编程|字节研发设施下的 Git 工作流
本文插图
图片来源:https://nvie.com/posts/a-successful-git-branching-model/
初级 Git 开发者 , 面对这满图的分支和 merge 指向 , 简直想手撕作者 。 高级 Git 开发者要将这个流程运用实践也大感头疼 。
Git Flow 有不少优点:
? 分支各司其职 , 覆盖大部分开发场景 。
? 预期 master 分支中任何 commit 都是可部署的 。
? 严格按照流程执行 , 出现重大事故的情形会大大降低 。
缺点也不少:
? 过于繁琐 , 无法要求所有团队成员按照这个流程严格执行 。
? 违反 git 提倡的 short-lived 分支原则 。
? master 分支历史记录并不干净 , 只能通过打 Tag 标记哪些是 master 真正要部署的 。
? 对持续部署和 monorepo 仓库不友好 。 GitHub Flow
GitHub Flow 是一个基于分支的轻量级工作流 。 它突出了 CR 的重要性 , 有助于我们掌握 CR 的开发模式 , 但它没有解答部署、环境、发布、集成等问题 。

技术编程|字节研发设施下的 Git 工作流
本文插图
图片来源:https://guides.github.com/introduction/flow/index.htmlGitLab Flow
GitLab Flow 并不像 Git Flow, GitHub Flow 一样具有明显的规范 , 它更多是在 GitHub Flow 基础上 , 综合考虑环境部署、项目管理等问题而得出的一种实践 。 基于环境:

技术编程|字节研发设施下的 Git 工作流
本文插图

技术编程|字节研发设施下的 Git 工作流
本文插图
图片来源:https://docs.gitlab.com/ee/topics/gitlab_flow.html基于发布计划:

技术编程|字节研发设施下的 Git 工作流
本文插图
【技术编程|字节研发设施下的 Git 工作流】图片来源:https://docs.gitlab.com/ee/topics/gitlab_flow.htmlTrunk-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 周期包含 。

技术编程|字节研发设施下的 Git 工作流
本文插图
图片来源:https://paulhammant.com/2013/04/05/what-is-trunk-based-development/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 过程中疯掉 。

技术编程|字节研发设施下的 Git 工作流
本文插图
图片来源:https://developer.aliyun.com/article/573549公司实践
字节跳动的 Web 服务都跑在私有云 CE (Compute Engine) 中 , 部署产物则由统一的代码编译发布和版本管理平台分发 , 每个构建产物都有一个 AR (Artifact Repository) 管理 。 多环境部署现状服务端视角
服务端微服务跑在 CE 上 , 代码编译由 AR 完成 , CE 和 AR 是 1:N 的关系 , 一个应用的运行依赖多个 AR , 在进行环境管理时 , 需要以 CE 为纬度来区分 。从 CE 视角来看 , 公司有 5 类环境(以国内产品为例):

技术编程|字节研发设施下的 Git 工作流
本文插图
通过 headers -H 'x-env-tag:{env}' 将流量导向不同环境 , 满足“开发测试”、“QA 测试”、“预发测试”、“小流量测试”、“全量上线” 各阶段的测试需求 。
CE 测试环境服务示例:

技术编程|字节研发设施下的 Git 工作流
本文插图
前端视角
前端和服务端有差异 , 一个 URL path 访问的资源通常由一个 AR 产出 , URL paths 和 AR 是 N:1 关系 , 所以前端部署以 AR 版本来区分环境:

技术编程|字节研发设施下的 Git 工作流
本文插图
前端部署可为测试环境和产品预览环境生成独立的域名进行测试 , 也可通过设定 headers -H 'x-env-tag:{env}' 进行环境导流 。 团队实践的 Git 工作流
结合前后端的环境现状 , 可整理三类研发流程:
功能测试流程(测试环境)
QA 提测流程(测试环境)
上线发布流程(测试、预发、灰度、线上环境)
公司内目前有三种 Git 工作流与之对应:
? 小步快跑:单主干

技术编程|字节研发设施下的 Git 工作流
本文插图
小步快跑:单主干
? 周期发版:双主干
分页标题
技术编程|字节研发设施下的 Git 工作流
本文插图
周期发版:双主干
? 周期发版:三主干

技术编程|字节研发设施下的 Git 工作流
本文插图
周期发版:三主干
对比“双主干”和“单主干” ,
有联系:
处于 MR 状态的迭代分支 ≈≈ 研发主干 Dev
单主干 Master ≈≈ 发布主干 Master
也有区别:
单主干的“研发分支”不存在一个固定的测试环境(相较于双主干 dev 分支)
多个 feature 同时发测试环境时需要组合成新分支 , 管理不便
单主干迭代分支在 MR /非 MR 状态下的 CI 流水线有差异单主干实践前端微服务管理平台
字节前端微服务平台属于成熟业务 , 只需做少量 feature/fix 开发 , 在工作流上采用单主干模式 。

技术编程|字节研发设施下的 Git 工作流
本文插图
本地测试后 , 不再经过功能测试环境测试 。 发起 Merge Request , CR 通过合码后 , 上测试基准环境进行测试 , 如发现问题 , 回滚 , 进入下一轮 CR 。
虽然小修小改影响风险小 , 但流程缺乏进入功能测试环境的流程 , 还是存在隐患 , 有可能影响测试环境的业务方使用 , 不是很好的实践 。
单主干只适应于业务规模小 , 成熟度高无大改动的项目 。 但无论业务规模如何 , 执行上线发布流程前 , 都必须先经过线下环境验证 。 双主干实践私有云平台
云平台的 Git 工作流是由繁入简的过程 。 最开始为每个部署环境设定了一个部署分支 。 feature 分支的 commit 点需要和三个环境的部署分支发生 merge , 起不到串联测试的目的 。

技术编程|字节研发设施下的 Git 工作流
本文插图
经过改进后 , 采用标准的 Trunk-based Flow , 仍能满足 online/sandbox/boe 三个环境的部署要求 。

技术编程|字节研发设施下的 Git 工作流
本文插图
云平台参与业务方有上百个(类似阿里云平台) , 虽然图中仅展示了三个环境 , 但实际上 5 大环境的使用都融入了日常开发中 。 某业务中台
某业务中台的 Git 工作流重点阐述了同一个项目多人协作开发时会遇到的问题:
多个 feature 各自独立提测, 临近上线合码时有较多冲突, 可能导致线上 bug
提测前和提测中, 如果 master 更新了, 可能没有及时同步下来, 上线前合入 master 可能会导致冲突或 bug
在流程设计上 , master 作为发布分支 , release-* 为提测分支 , 结合了单主干的便捷(hotfix 直接和 master 交互)和双主干对 feature 的管理
和 Trunk-based Flow 刚好相反 , 主分支是发布分支 , 提测分支是短期的
另一个比较有特点的是 , 在 release 测试过程中 , 发现某个 feature 的 bug ,直接从 release 分支 checkout 出来进行修复 , 并再次合入 release

技术编程|字节研发设施下的 Git 工作流
本文插图
Jupiter 工作流规范
Jupiter 是字节 Web 开发引擎 , 覆盖 Web、组件库、BFF、SSR 等前端开发领域 。 Jupiter 推荐 Trunk-based Flow 类似的 Flow , 并从 CI/CD 角度出发 , 在开发新需求、hotfix 等时机给出 Git 操作建议 。
有重叠人员参与的各项目之间有一致的流程和模式 , 避免增加认知负担 , 避免同一个人在不同项目之间切换时混淆和迷惑 , 也能集中力量做实践和改进 , 共享经验和基础建设 。
上线节奏要灵活 。 既照顾早期的项目 , 也照顾规模化落地的项目 , 考虑到项目在追求不同里程碑时 , 上线频率会有变化 。 所以每周上线一次、每天上线一次(适合人多、稳定性要求高的项目)、一天内分多次上线多个 feature , 都有可能 , 不能限定一个固定的节奏 。 任何人 , 在任何时候都可以发起上线 。分页标题
支持 monorepo 。 不同方向不同人参与的项目 , 可能会共用一个仓库 , 方便复用代码和基础设施 。 所以仓库中不同项目可能有不一样的上线节奏和上线需求 。
鼓励持续集成(CI) , 集成不等同于部署 , 发 MR 集成代码的时候不用有压力 , 不会在不知情的情况下被上线 。 也鼓励持续部署(CD) , 部署不等于发布 , 不能发布的代码 , 在正式上线前有机会关掉 。
上线过程必须是固定、重复、能统一改进 , 能逐步增加自动化的 , 不能每次上线时重新、临时规划或修改上线方法 , 增加负担和成本 。
CI 是 CD 的前提 , 没经过 CI 的修改不能进入 CD 环节 。
不能有任何修改不经过 staging(预发布 , 尽可能跟线上一致)测试 , 直接上线 。
CI 和 CD 的历史记录要绝对可靠、可追溯 , 只能增加 , 不能减少和修改 。
尽可能减少手动操作环节 , 避免在特定的个人机器上做上线操作 。 三主干实践亿级 App
App 发版应该是目前为止最为复杂的分支管理场景了 。 客户端安装包一旦下发到渠道被用户下载 , 如果无法通过热更新修复 , 将严重影响 App 用户留存 。App 发版具有更规范的发版规律 , Feature Toggle 必不可少 , 当我们觉得 CR , CI/CD 麻烦时 , 对比开发上线一个影响上亿用户的 App feature , 是不是感觉做 Web 的 CI/CD 简单多了?

技术编程|字节研发设施下的 Git 工作流
本文插图
总结
本文尽可能从多角度阐述 Git 工作流的使用姿势 , 希望对大家有帮助 。 Git 工作流是为了上线有保障 , 上线过程中充分测试必不可少 , 良好的 Git 工作流能保障测试是渐进且可靠的 。 环境管理和 Git 工作流结合在头条内部也形成了很多规范 , 包括「环境部署」、「流量调度」、「连通性测试」等使用规范;「限定场景允许」、「暂时场景允许」、「限定流程允许」等环境约束规范 。 再结合 CI/CD , 我们就可以全链路保障业务的快速迭代、安全上线 。 参考资料
Trunk-based Development vs. Git Flow (https://www.toptal.com/software/trunk-based-development-git-flow)
Please stop recommending Git Flow!(https://georgestocker.com/2020/03/04/please-stop-recommending-git-flow/)
Understanding the GitHub flow(https://guides.github.com/introduction/flow/index.html)
Introduction to GitLab Flow(https://docs.gitlab.com/ee/topics/gitlab_flow.html)
https://cn.trunkbaseddevelopment.com
在阿里 , 我们如何管理代码分支? (https://developer.aliyun.com/article/573549)
谷歌的代码管理 (http://www.ruanyifeng.com/blog/2016/07/google-monolithic-source-repository.html)
欢迎关注「字节前端」
简历投递联系邮箱「tech@bytedance.com」