譯者 | 劉汪洋
審校 | 重樓
概括:這篇文章介紹了 Merge Queue 這一新的代碼合并方式,它可以讓開發(fā)者不用擔(dān)心代碼沖突和等待時間,而是把合并的任務(wù)交給一個自動化的隊列來處理。文章還介紹了一個實現(xiàn)了 Merge Queue 的工具 Mergify,它可以與 GitHub 集成,讓開發(fā)者更方便地使用 Merge Queue。
盡管幾個月前“合并隊列”還是一個不太為人所知的術(shù)語,現(xiàn)在卻越來越受到業(yè)界的重視。無論是像 GitHub 這樣的行業(yè)領(lǐng)袖的公告,還是實際的技術(shù)解決方案,合并隊列正逐漸被軟件開發(fā)團(tuán)隊所采納。
因此,你可以深入探討這一主題,了解合并隊列的定義,其適用場景,以及它們在實際操作中的工作原理。
準(zhǔn)備好了嗎?讓我們開始吧。
“合并隊列”是什么?
在探討為何要使用合并隊列之前,我們首先需要明確它的定義。
顧名思義,合并隊列是一系列等待合并的 Pull Request (簡稱 PR)的排列順序。
每位團(tuán)隊成員每天都可能創(chuàng)建許多 Pull Request,然后由倉庫維護(hù)者將其加入隊列。聽起來很簡單,不是嗎?
更準(zhǔn)確地說,你不僅僅是將基礎(chǔ)的 PR 加入隊列。隊列中的所有 PR 都已經(jīng)得到了維護(hù)者的批準(zhǔn),這意味著它們已經(jīng)通過了所有必要的檢查。
因此,你得到了一個充滿已驗證 Pull Request 的隊列。這聽起來很有趣,但似乎并不實用。為什么不逐一合并它們呢?為了解答這個問題,我們先來看看如果你不使用合并隊列,可能會遇到哪些常見問題。
為什么需要合并隊列?
坦白說,有許多理由支持使用合并隊列。在這一部分,你將了解一個真正棘手的問題,以及如何通過使用合并隊列來解決它。
常見問題:合并過時的 Pull Request
要理解合并隊列如何解決問題,你首先必須了解問題本身。
請想象以下場景:
- 主分支已經(jīng)通過了持續(xù)集成測試。
- 創(chuàng)建了一個 Pull Request,并通過了 持續(xù)集成(CI),我們稱之為 PR1。
此時,你可以通過以下圖示來表示倉庫的狀態(tài):
image.png
目前一切似乎都在正常運行,但這種情況并不會持續(xù)下去。讓我們深入了解一下。
當(dāng) PR1 仍處于打開狀態(tài)時,主分支接收了另一個提交。無論這個新提交是直接推送到主分支還是從另一個 Pull Request 合并的,關(guān)鍵是主分支已經(jīng)發(fā)生了變化。
隨后,持續(xù)集成(CI)系統(tǒng)針對主分支運行了測試,并再次通過。此時,你可以通過以下圖示來描述你的倉庫及其持續(xù)集成系統(tǒng)的狀態(tài):
image.png
你會注意到 PR1 仍被持續(xù)集成系統(tǒng)視為有效,這是合理的,因為只有主分支發(fā)生了變化,而 PR1 并未發(fā)生改變。
由于代碼之間沒有沖突,GitHub 認(rèn)為 PR1 是可以合并的,合并按鈕變成了綠色。
你滿懷信心地點擊了那個綠色按鈕。
然而,正如你所預(yù)料,這可能會帶來一個意外的“驚喜”——并不是好事。
現(xiàn)在,當(dāng)你試圖合并 PR1 并創(chuàng)建了一個新的合并提交時,持續(xù)集成測試卻失敗了。為什么會這樣呢?
image.png
實際上,當(dāng) PR1 被標(biāo)記為有效時,CI 并沒有用主分支新添加的提交再次測試 PR1。
然而,主分支中的最后一個提交引入了新的測試,而 PR1 并未包含正確的代碼來通過這個新測試,這一情況雖讓人沮喪,但卻合情合理。
如何應(yīng)對這一挑戰(zhàn)?
這個問題的核心在于 Rebase 的操作以及每個 Pull Request 需要與主分支保持最新的必要性。如果你不采用合并隊列,通常有兩個選擇:
- 僅在功能分支的頂部運行持續(xù)集成,不強(qiáng)制功能分支與主分支保持同步。主要缺點是功能分支可能與主分支兼容,但也可能不兼容。
- 要求所有功能分支與目標(biāo)分支保持最新。主要缺點在于這會消耗大量的時間和資源。
對于采用持續(xù)集成/持續(xù)交付(CI/CD)流程的組織和團(tuán)隊來說,這是一種常見的挑戰(zhàn)。如果你正面臨這個問題,不必?fù)?dān)心,因為真正的解決方案已經(jīng)找到了!
真正的解決方案:合并隊列
解決方案就是使用合并隊列。它在合并之前會更新所有與主分支不同步的 Pull Request。實際上,合并隊列會要求 CI 系統(tǒng)使用主分支的最新代碼重新測試 PR。
如果你在之前描述的情況下使用合并隊列,系統(tǒng)會自動將主分支合并到功能分支中。
如下圖所示,CI 將重新運行測試。如果 Pull Request 失敗,則會被標(biāo)記為失敗并從隊列中移除。當(dāng)然,如果 PR 有效,并且所有檢查都通過了,它將被合并。
image.png
另一個實際場景:多個 Pull Request 已驗證,準(zhǔn)備合并。
合并隊列會按照順序安排這些 Pull Request 的合并,并確保它們與主分支保持同步。當(dāng)然,只有當(dāng) Pull Request滿足所有條件時,才會進(jìn)行同步更新。
但是,如果你剛合并了一個已更新的 Pull Request,緊接著又發(fā)現(xiàn)另一個 Pull Request 仍然過時,那會發(fā)生什么情況呢?為了更清晰地解釋這個過程,我們可以通過下圖來理解:
image.png
合并隊列的作用是確保在合并之前,第二個 Pull Request 與主分支的最新版本保持同步。通過這樣的操作,可以避免將過時或有缺陷的 Pull Request 合并到主分支中。
image.png
你可以根據(jù)需要重復(fù)這個過程,逐一處理隊列中的每個過時 Pull Request。
雖然軟件開發(fā)的過程并不總是簡單,但合并隊列的使用無疑可以讓整個流程變得更加順暢和高效。
合并隊列的工作機(jī)制
了解合并隊列能解決的問題后,我們來深入探討其工作機(jī)制。
合并隊列在視覺上可能顯得有些復(fù)雜,我們可以逐步分析其工作流程和組成部分。
1. 將有效的 PR 加入隊列
合并隊列引擎會在你的 Pull Request 上運行。所有滿足條件的 Pull Request 將被添加到隊列中。
2. 更新與 CI
合并隊列會確保隊列中的每個 PR 與主分支保持同步,以確保其最新狀態(tài)。
隨后,CI 會重新運行,以確認(rèn) PR 是否可以合并。
3. 合并還是不合并:決策點
存在兩種截然不同的情況:
- 所有檢查通過 → 合并 PR。
- 測試失敗 → 將 PR 從隊列中移除。
Mergify 的合并隊列特點是什么?
具體來說,Mergify 的合并隊列實現(xiàn)了你剛剛了解的所有功能。
作為市場上首批合并隊列之一,Mergify 已經(jīng)贏得了數(shù)千名用戶的滿意評價。
雖然前述的常見功能足以解決許多棘手問題,但在更復(fù)雜和特定的情況下,你可能需要一些非常具體的功能。
幸運的是,Mergify 可以滿足這些需求!
1. 推測性檢查:并行測試不同的 PR
隊列中的第一個 Pull Request 將被加入合并流程,并與其他請求一起并行測試,以便更快地合并。
image.png
2. 批次處理:一次檢查和合并多個 PR
Mergify 通過 batch_size 選項允許一次性檢查多個 Pull Request 的合并性。
3. 多隊列管理:將 PR 分配到專用隊列
通過使用多個隊列,可以根據(jù)優(yōu)先級將 Pull Request 分配到不同的隊列中。
4. 隊列凍結(jié):暫停所有合并過程
Mergify 允許暫停一個或多個隊列的合并過程,從而增強(qiáng)了對代碼合并方式、時間的控制和靈活性。
5.優(yōu)先級管理:優(yōu)先處理特定 Pull Request
你可以根據(jù)標(biāo)簽、所有者等因素選擇哪個 PR 應(yīng)該首先合并。最終的決策權(quán)在你手中!
結(jié)論
現(xiàn)在,各位讀者應(yīng)該對合并隊列的概念有了全面的了解,從工作原理到使用的理由,這一概念對你來說應(yīng)該已經(jīng)一目了然。如果你想使用 Mergify 的合并隊列解決方案,可以去官網(wǎng)進(jìn)一步詳情。
譯者介紹
劉汪洋,51CTO社區(qū)編輯,昵稱:明明如月,一個擁有 5 年開發(fā)經(jīng)驗的某大廠高級 Java 工程師,擁有多個主流技術(shù)博客平臺博客專家稱號。
原文標(biāo)題:What's a Merge Queue and Why Use it?,作者:Wakatepe-mergify