什么是 Merge Queue,为什么要使用它?
译者 | 刘汪洋
审校 | 重楼
概括:这篇文章介绍了 Merge Queue 这一新的代码合并方式,它可以让开发者不用担心代码冲突和等待时间,而是把合并的任务交给一个自动化的队列来处理。文章还介绍了一个实现了 Merge Queue 的工具 Mergify,它可以与 GitHub 集成,让开发者更方便地使用 Merge Queue。
尽管几个月前“合并队列”还是一个不太为人所知的术语,现在却越来越受到业界的重视。无论是像 GitHub 这样的行业领袖的公告,还是实际的技术解决方案,合并队列正逐渐被软件开发团队所采纳。
因此,你可以深入探讨这一主题,了解合并队列的定义,其适用场景,以及它们在实际操作中的工作原理。
准备好了吗?让我们开始吧。
“合并队列”是什么?
在探讨为何要使用合并队列之前,我们首先需要明确它的定义。
顾名思义,合并队列是一系列等待合并的 Pull Request (简称 PR)的排列顺序。
每位团队成员每天都可能创建许多 Pull Request,然后由仓库维护者将其加入队列。听起来很简单,不是吗?
更准确地说,你不仅仅是将基础的 PR 加入队列。队列中的所有 PR 都已经得到了维护者的批准,这意味着它们已经通过了所有必要的检查。
因此,你得到了一个充满已验证 Pull Request 的队列。这听起来很有趣,但似乎并不实用。为什么不逐一合并它们呢?为了解答这个问题,我们先来看看如果你不使用合并队列,可能会遇到哪些常见问题。
为什么需要合并队列?
坦白说,有许多理由支持使用合并队列。在这一部分,你将了解一个真正棘手的问题,以及如何通过使用合并队列来解决它。
常见问题:合并过时的 Pull Request
要理解合并队列如何解决问题,你首先必须了解问题本身。
请想象以下场景:
- 主分支已经通过了持续集成测试。
- 创建了一个 Pull Request,并通过了 持续集成(CI),我们称之为 PR1。
此时,你可以通过以下图示来表示仓库的状态:
image.png
目前一切似乎都在正常运行,但这种情况并不会持续下去。让我们深入了解一下。
当 PR1 仍处于打开状态时,主分支接收了另一个提交。无论这个新提交是直接推送到主分支还是从另一个 Pull Request 合并的,关键是主分支已经发生了变化。
随后,持续集成(CI)系统针对主分支运行了测试,并再次通过。此时,你可以通过以下图示来描述你的仓库及其持续集成系统的状态:
image.png
你会注意到 PR1 仍被持续集成系统视为有效,这是合理的,因为只有主分支发生了变化,而 PR1 并未发生改变。
由于代码之间没有冲突,GitHub 认为 PR1 是可以合并的,合并按钮变成了绿色。
你满怀信心地点击了那个绿色按钮。
然而,正如你所预料,这可能会带来一个意外的“惊喜”——并不是好事。
现在,当你试图合并 PR1 并创建了一个新的合并提交时,持续集成测试却失败了。为什么会这样呢?
image.png
实际上,当 PR1 被标记为有效时,CI 并没有用主分支新添加的提交再次测试 PR1。
然而,主分支中的最后一个提交引入了新的测试,而 PR1 并未包含正确的代码来通过这个新测试,这一情况虽让人沮丧,但却合情合理。
如何应对这一挑战?
这个问题的核心在于 Rebase 的操作以及每个 Pull Request 需要与主分支保持最新的必要性。如果你不采用合并队列,通常有两个选择:
- 仅在功能分支的顶部运行持续集成,不强制功能分支与主分支保持同步。主要缺点是功能分支可能与主分支兼容,但也可能不兼容。
- 要求所有功能分支与目标分支保持最新。主要缺点在于这会消耗大量的时间和资源。
对于采用持续集成/持续交付(CI/CD)流程的组织和团队来说,这是一种常见的挑战。如果你正面临这个问题,不必担心,因为真正的解决方案已经找到了!
真正的解决方案:合并队列
解决方案就是使用合并队列。它在合并之前会更新所有与主分支不同步的 Pull Request。实际上,合并队列会要求 CI 系统使用主分支的最新代码重新测试 PR。
如果你在之前描述的情况下使用合并队列,系统会自动将主分支合并到功能分支中。
如下图所示,CI 将重新运行测试。如果 Pull Request 失败,则会被标记为失败并从队列中移除。当然,如果 PR 有效,并且所有检查都通过了,它将被合并。
image.png
另一个实际场景:多个 Pull Request 已验证,准备合并。
合并队列会按照顺序安排这些 Pull Request 的合并,并确保它们与主分支保持同步。当然,只有当 Pull Request满足所有条件时,才会进行同步更新。
但是,如果你刚合并了一个已更新的 Pull Request,紧接着又发现另一个 Pull Request 仍然过时,那会发生什么情况呢?为了更清晰地解释这个过程,我们可以通过下图来理解:
image.png
合并队列的作用是确保在合并之前,第二个 Pull Request 与主分支的最新版本保持同步。通过这样的操作,可以避免将过时或有缺陷的 Pull Request 合并到主分支中。
image.png
你可以根据需要重复这个过程,逐一处理队列中的每个过时 Pull Request。
虽然软件开发的过程并不总是简单,但合并队列的使用无疑可以让整个流程变得更加顺畅和高效。
合并队列的工作机制
了解合并队列能解决的问题后,我们来深入探讨其工作机制。
合并队列在视觉上可能显得有些复杂,我们可以逐步分析其工作流程和组成部分。
1. 将有效的 PR 加入队列
合并队列引擎会在你的 Pull Request 上运行。所有满足条件的 Pull Request 将被添加到队列中。
2. 更新与 CI
合并队列会确保队列中的每个 PR 与主分支保持同步,以确保其最新状态。
随后,CI 会重新运行,以确认 PR 是否可以合并。
3. 合并还是不合并:决策点
存在两种截然不同的情况:
- 所有检查通过 → 合并 PR。
- 测试失败 → 将 PR 从队列中移除。
Mergify 的合并队列特点是什么?
具体来说,Mergify 的合并队列实现了你刚刚了解的所有功能。
作为市场上首批合并队列之一,Mergify 已经赢得了数千名用户的满意评价。
虽然前述的常见功能足以解决许多棘手问题,但在更复杂和特定的情况下,你可能需要一些非常具体的功能。
幸运的是,Mergify 可以满足这些需求!
1. 推测性检查:并行测试不同的 PR
队列中的第一个 Pull Request 将被加入合并流程,并与其他请求一起并行测试,以便更快地合并。
image.png
2. 批次处理:一次检查和合并多个 PR
Mergify 通过 batch_size 选项允许一次性检查多个 Pull Request 的合并性。
3. 多队列管理:将 PR 分配到专用队列
通过使用多个队列,可以根据优先级将 Pull Request 分配到不同的队列中。
4. 队列冻结:暂停所有合并过程
Mergify 允许暂停一个或多个队列的合并过程,从而增强了对代码合并方式、时间的控制和灵活性。
5.优先级管理:优先处理特定 Pull Request
你可以根据标签、所有者等因素选择哪个 PR 应该首先合并。最终的决策权在你手中!
结论
现在,各位读者应该对合并队列的概念有了全面的了解,从工作原理到使用的理由,这一概念对你来说应该已经一目了然。如果你想使用 Mergify 的合并队列解决方案,可以去官网进一步详情。
译者介绍
刘汪洋,51CTO社区编辑,昵称:明明如月,一个拥有 5 年开发经验的某大厂高级 Java 工程师,拥有多个主流技术博客平台博客专家称号。
原文标题:What's a Merge Queue and Why Use it?,作者:Wakatepe-mergify