譯者 | 劉汪洋
審校 | 重樓
概括:這篇文章介紹了 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