淺談開發流程 — Git Flow 到 Trunk-Based Development 的團隊經驗雜談

Shanpig
17 min readOct 27, 2022

楔子

相信所有的前端工程師都曾經在面試的時候被問過這個問題。

請問你有學過 git flow 嗎?

有基本 google 能力的人想必都能夠很快找到答案並看懂概念,甚至可以查到更多諸如 gitlab flow、github flow 等等其他的專案開發流程。但實際上在工作上,是否真的會應用到這些概念呢?到底為什麼會需要 git flow 呢?不同的 flow,又有什麼好與壞?

進入職場後的第一個團隊,便很幸運的有一個完整的開發流程,而且在近期也因為各種痛點,進行了一次大規模的開發流程調整,從過去常聽見的 git flow,轉為了更為簡潔,卻對我而言相當陌生的 TBD 流程。

第一次聽到 TBD 的感想是:這到底是個什麼東西?為什麼大家傳的神乎其技,好像 git flow 在他面前完全不值一提一樣?趁著團隊內轉移到 TBD 有一小段時間了,便來記錄一下自己的所見所聞,以及實際開發上的差異。

Git flow 介紹

什麼是 git flow?

git flow 一共分成五個主要的分支,各自負責不同的開發和流程,分別為 masterreleasedevelopfeaturehotfix

Master

master 分支通常是正式上線&部署時的 target branch,上面的內容必須是完整的 feature,因此所有的改動都必須從其他的 branch 合併過來(可以是 cherry-pick 或是 merge,依使用情況而定)。

在一個版本正式上線後,也通常會用 git tag 指令在這個 branch 上面進行版本號的更新。

Release

release 分支聽起來像是正式上線的分支,但他的實際目的比較像是 alpha release,在正式上線到 production 之前,先上線到另一個測試環境,這個測試環境通常會比 local 的 develop branch 更完整,例如有更多的正式資料、更貼近實際場景的登入帳號、更像是正式環境的部署環境等等。加上因為這個 branch 是在上線前的最後確認,他會與 master 的內容非常相近,可以更為貼切的模擬上線後的行為。

因此在有 QA 和設計師的團隊中,通常會在這個時間點將 feature 交付給 QA 做完整的 regression test,以及設計師做最後的 design review,以測試較完整的頁面與功能,並檢查是否有問題。

Develop

這個分支比 release 更接近開發時期。所有的功能(feature branch)都會從這個分支出去,並且在完成後 merge 回這個分支。因此在開發階段,這個分支會常常更新,而後在 release 階段,合併到 release branch。release 完後,若有任何 hotfix,會在 master branch 上修改後 merge 回 develop。

Feature

大部分的功能開發會在這個分支進行。通常存活的時間只有一個 PR,之後就會 merge 到 develop 並關閉分支。

Hotfix

正式上線後,如果有任何影響使用的緊急問題,會直接從 master 直接開一個 hotfix 分支,緊急修復後 merge 回 master,並且同時 merge 到 develop,避免在下一次 release 時,修復被新的 feature 覆蓋掉。

什麼時候適合使用 git flow?有什麼優缺點?

git flow 的優點便是區分明確。

每一個分支都有它的主要功能,並且也明確定義了各個分支的生存週期,以及彼此之間的合併、分支方式,對於第一次接觸 development flow 的開發者而言是最容易理解並應用的一種方式。因此如果團隊成員對於開發流程並不熟悉,通常以這種開發模式可以很好的引入,並且避免品質未達標的程式碼,只經過一次 review 便進入 master。同時,將各個階段拆分開後,開發者以外的團隊成員(如 QA、設計師、PM 等等)也能夠知道在哪裡測試已經上線的功能。

然而他的缺點也同樣明顯,正因為分工明確,每一個完整的開發流程需要經過多次的 PR。最基本的功能開發便會經過 feature -> develop -> release -> master 的三次 merge 流程,每一次 merge 都將有機會產生 merge conflict,而 conflict 發生會增加邏輯錯誤的機率,因為解 conflict 的開發者不一定會知道其他開發者的開發順序。如果解 conflict 的過程發生錯誤,將會增加開發者的維護上的成本。

git flow 開發流程圖

如果仔細看整個 git flow 的開發流程就會發現,其實整個流程是相當複雜且混亂的,且其中會發生大量的分支交互,進而影響彼此之間的時序關係。另外,在許多 git flow 反對者的論點中,都會提到 git flow 的 develop branch 是多餘且無意義的分支,在開發期的前後,實際上 master 和 develop branch 都會需要互相同步,這代表工程師其實理論上是可以直接在 master 上進行開發的。

再者,在一個有持續整合交付(CI / CD)流程的團隊中,通常 PR merge 前都需要跑一些自動化測試,這些測試一樣有時間成本,因此經過的 PR merge 越多,其時間成本將會更多,導致開發流程無法彈性快速的進行。

實際的個人使用心得

剛加入我所在的團隊時,我們團隊使用的是正常的 git flow。我們共有 develop(staging)、alpha、production 三個環境,並且也像正統 git flow 一樣走五種分支的開發流程。以下我按照「一般功能開發」、「alpha release」、「production release」、「hotfix 修復」等四個流程來逐一說明我們遇到的問題。

一般功能開發

在開發階段,我們會從 develop 開 feature branch 進行開發,並且發 PR merge 到 develop,如果有多個人同時改到相同部分程式碼,會在這個階段進行解 conflict 的動作。同時修復一般的 bug 也會是一樣的流程。每次 PR merge 到 develop 後,便會交由 github actions 進行自動化的 staging 環境部署。

此時對於開發者而言並沒有什麼問題,因為大部分的功能都在同一隻 branch 內進行迭代,因此都能很快的發現錯誤。

Alpha Release

當進入 alpha 階段時,我們透過 github actions 自動從 develop branch 發一隻 merge PR 到 alpha branch,以把開發期的內容帶到 alpha 環境,如果 release manager 確認沒有問題後,便會將 PR merge,並且將 merge 資訊帶給團隊,之後交給 CircleCI 進行 alpha 環境的自動化部署。

在 alpha release 後,會有兩種情況需要額外增加 alpha 的內容,在 PR merge 到 develop 之後,手動 cherry-pick 到 alpha 上。

  1. 在 QA 測試和設計師 design review 的過程中,會有許多 bug 被 QA 測試出來。開發者需要在 production release 前修復。
  2. 時程的延宕、緊急任務的加入、較重要的重構或樣式修正等等需要一起上 alpha 的內容。

這裡會發生一些不太理想的情況:

1. 不同 PR 之間的時序問題

由於不同人開發的內容有可能互相影響,開發者在 cherry-pick 時便會遇到有相依性的 commits,必須要以正確的順序同時被 pick 到 alpha。

這對於開發者而言是較大的負擔,因為若是任務拆分不夠明確,或是 bug 本身問題涵蓋較大,就會需要多個開發者同時處理。即便兩個 PR 之間並沒有功能上的相依性,也可能會因為修改到同一份檔案,產生先後順序的相依性。而每個開發者的開發進度又不同,便有機會造成「應該後進的 PR 先被 pick 進 alpha」而導致的邏輯錯誤。

2. 不同 PR 之間的相依性問題

在正式的 alpha release 時期,由於時程關係,部分人的任務已經完成,但可能還有一些人持續在進行中,因此便會出現「有些人已經在修 p2 以下的 bug、重構、偷跑下個 sprint」等等「不需要進入 alpha」的內容。而由於通常重構或修復 bug 會動到的程式碼較為分散,如果開發者的開發習慣是邊重構邊開發,而且 PR 拆分不夠明確,將有很大的機會造成「明明不需要上 alpha 的 PR,卻因為動到相關 code 而需要跟著上 alpha」的窘境,甚至是為了不讓他上車而造成極難解決的 conflict。

3. Alpha release 大塞車

第三個問題,則是因為我們為了保證 alpha 的一致性,打開了 Require branches to be up to date before merging 的檢查,因此在 alpha 上一次只能有一個 PR 進行 merge process。一旦 merge 了一個 PR,其他的 PR 將會被視為 out-of-date,必須重新 rebase。而我們的 PR merge 都設有各種 CI 流程(包含 linting、unit test、e2e test、bundling & deploy 等等),因此相當於是有多少 merge to alpha 的 PR,就需要等待多少個 alpha CI 流程,極大的增加了時間成本。

Production Release

在準備進行 production release 時,github actions 一樣會從 alpha 開一個 release PR 到 master。release manager 會需要確認已經將所有應該 release 的 PR 都 pick 到 release PR 中,如同 alpha release 一樣。由於 alpha 有 require up to date 設定,較不會遇到 conflict 的狀況。

Hotfix

在正式上線後,如果遇到太嚴重的問題,我們會需要進行 hotfix。這個內容雖然較為急迫,但通常為了安全起見,我們還是會從 develop 開 bugfix branch 修復後,再使用 3 PR 的方式進行 merge(對 develop、alpha、master 同時開三隻 PR)。而最後一個 PR merge 需要等到 QA 驗證通過後才會 merge,也就是至少要等待三次的 CI 流程。這造成的問題便是大大增加了從修復到正式上線的時間。

插播兩個前情提要

由於 TBD 的概念與 github flow 及 gitlab flow 都非常相近,因此在這裡還是分別簡單介紹一下,用 git flow -> github flow -> gitlab flow -> TBD 的過渡方式,會更加容易理解。

什麼是 github flow?

基於「develop 無用論」,github flow 簡化了 git flow 的流程,將分支減少到了三種:masterfeaturehotfix

開發流程可以直接簡化成上面的流程:從 master 開 feature/hotfix 分支,並且透過 PR 直接 merge 回 master。

移除了 develop 和 release branch 之後,開發流程從多個 PR merge 簡化成了一個,所有的修改內容將被直接整合到 master 上。

大部分的 development flow 通常都會有一個共識,那就是 master 上的所有 commit 都應該被視為是可以部署的,因此在 git flow 的流程中,為了將開發環境和正式環境拆分,會需要多出較多的分支與合併過程,大大增加了開發的成本。但實際上,部署環境和開發環境的拆分,不一定要透過 release PR 和獨立維護的 develop branch 來達成。

另一個跟 git flow 不同的地方在於部署階段,git flow 還需要有一個 merge 回 develop 的過程,這個過程的目的是在同步 develop 與 master,但在 github flow 中,這個過程直接被省略了,因為開發者本來就是對 master 進行推送。

當任何一個 PR merge 時,根據 github flow 的原則,必須盡快進行部署,因此在 merge 之後,正式環境便會直接得到更新後的內容。

什麼時候適合使用 github flow?有什麼優缺點?

github flow 大量簡化了 git flow 在流程化上產生的負擔,在保持開發流程的同時減輕了開發以外的時間與認知成本。

這個流程對程式碼的品質有一定的要求,由於程式碼只經過一次的 review 便會直接進入 master 並部署到 alpha 甚至是 production,若對於團隊成員的程式碼較為嚴謹,或者規模較大的功能,用這種方式開發相對而言會有較多的風險。

另外,由於部署的對象會是 merge 回 master 的 commit,因此如果部署了當前的 merge commit,之前的所有改動都會跟著一起被 deploy。如果在過程中有尚未完成或是正在處理的 bug,甚至是解錯的 merge conflict,便會跟著一起上到 production,相對而言是比較有風險的,會需要開發者更細心的確保程式碼品質。

Trunk Based Development (TBD) 介紹

什麼是 TBD?

TBD 與 github flow 的流程十分相近,一樣只有三個 branch,但在部署流程上相對較為嚴謹。對 TBD 而言,master branch 是一個獨立的個體(trunk),所有的改動都在這個分支,所有的部署都從這個分支獨立出去,部署時必需要確認 PR merge 回 master 後,才能以 cherry-pick 的模式將其更新到部署環境上。

可以看見其流程除了 release 的位置以外,與 github flow 並沒有差別。

這個概念使得開發者的所有 feature PR 合併對象都必須是 master,而需要部署時,則是從 master 上開一個分支進行部署。即使有 hotfix 的修正,也需要在 master 上進行修正後,再 cherry-pick 到 release 分支上。

這可以避免掉 github flow 中仍然有可能出現的缺漏:feature branch 在 merge 回 master 時,並不是最新的內容,因此在其 release 後可能不會是最終的版本。

什麼時候適合使用 TBD?有什麼優缺點?

這樣的流程完全移除了同步 master 與 develop 的 merge back 步驟,避免掉了 release 過程中可能遇到的 conflict(並不是完全不會遇到,而是開發該 feature 的開發者在 feature PR 便會遇到,交給最熟悉改動的人解決,較不會遇到解錯 conflict 的問題)。在一些較小的團隊中,甚至可以直接對 remote master 推送 commit,減少 PR merge 所需的時間,達到更快速的交付。

由於 release branch 是直接從 master branch 分支出去,也不會遇到 github flow 可能遇到的 regression 問題。

雖然 TBD 解決了很多 git flow 的問題,但他也有相對應的缺點。由於每次的 release 都開了新的分支,因此開發者需要非常清楚知道當前 release branch 的 branch name(通常是當前開發版本號),避免送錯 branch。這個問題相對輕微,透過第三方 hook 就可以解決(例如串接 github actions 到 slack message bot 通知所有開發者最新的 release branch 狀況)。

實際團隊&個人使用心得

在不久前我們的團隊正式轉換到了 TBD 的 workflow。原因便是 git flow 提出的痛點都可以在這樣的 workflow 中得到相當大的改善。我在這裡一樣用「一般功能開發」、「alpha release」、「production release」、「hotfix 修復」等四個流程來逐一說明我們現在的模式。

一般功能開發

開發者直接從 master 開 feature branch 進行開發,並且直接 merge 回 develop。github actions 在 master merge 被觸發時便會自動部署到 staging 環境。

alpha release

相較於 git flow 開一個 release PR,現在進入 alpha 階段後,github actions 會自動開一個 release branch,並且將這個 branch 部署到 alpha 上。

當 QA 測試出新的 bug,或是有尚未來得及上車的任務 merge 時,開發者需要自己將 merge commits 推送到該 release branch 上,並且觸發新一次的 alpha 環境部署。

這樣的流程由於省略了 develop to alpha 的 PR merge 過程,因此 conflict 只需要交給開發者在 feature branch merge 的時候處理即可,不會有 release manager 需要處理大量 conflict 的狀況出現。

Production Release

進入 production 階段時,release manager 只要確認所有該 sprint 需要的內容都已經進入 release branch,之後經過 QA 同意,直接觸發已經設定好的 github actions 進行 production 環境部署即可。由於 alpha 階段開發者都需要自行向 release branch 推送,到了 production 階段,release branch 就會是該 sprint 的最新版本,不再需要另行開 branch 部署,也不用多跑一次 CI。

Hotfix

在出現緊急 bugfix 的時候,開發流程便會直接走正常的開發流程,因此實際上只需要等待兩次的 CI 便可以正式上到 release branch 並部署到 alpha 與 production 上。

小結

目前爲止,使用 TBD 的感受上,好處仍然是遠遠大過缺點的,也歸功於我們的資深工程師大大的努力,讓整個開發流程可以更加順暢。當然每個 workflow 都有其存在的意義與使用情境,並不是每個團隊和情境都適合使用 TBD,還是會需要根據不同的狀況來判斷。我認為的 workflow 應該具備的特性,是「促進開發與持續整合交付的效率」,而不應該是一個「固有的傳統」。因此如果開發流程已經明顯的拖慢了開發進度,便應該嘗試進行調整,這也才符合敏捷開發「彈性、快速」的特性。

以上是我個人針對開發流程的理解以及實際體驗後的感想,如果有任何問題,或是有什麼缺漏或建議,都歡迎來訊和我討論!感謝你的閱讀

參考資料

tags: 前端

--

--