Git 分支管理策略彙總

原文鏈接: Git 分支管理策略

最近,團隊新入職了一些小夥伴,在開發過程中,他們問我 Git 分支是如何管理的,以及應該怎麼提交代碼?

我大概說了一些規則,但仔細想來,好像也並沒有形成一個清晰規範的流程。所以查了一些資料,總結出下面這篇文章,一共包含四種常見的分支管理策略,分享給大家。

Git flow

在這種模式下,主要維護了兩類分支:

  • 主要分支 (The main branch)
    • master
    • develop
  • 輔助分支 (Supporting branch)
    • feature branch (功能分支)
    • release branch (預發佈分支)
    • hotfix branch (熱修復分支)

master

首先,代碼庫應該有一個、且僅有一個主分支。master 分支的代碼永遠是穩定的,可以隨時發佈到生產環境。

develop

develop 分支用於日常開發,保存了開發過程中最新的代碼。

當 develop 分支上的代碼達到穩定,並且具備發版狀態時,需要將 develop 的代碼合併到 master,並且打一個帶有發佈版本號的 tag。

創建 develop 分支:

git checkout -b develop master

將 develop 合併到 master:

# 切換到 master 分支
git checkout master

# 對 develop 分支進行合併
git merge --no-ff develop

--no-ff 參數的作用是使當前的合併操作總是創建一個新的 commit 對象,即使該合併被執行爲快進式(fast-forward)合併。

這樣可以避免丟失掉該功能分支的歷史信息,並且將針對該功能的所有提交都集中到一起。這樣解釋也並不是很易懂,通過下圖來對比一下就比較明顯了:

feature

  • 分支來源:develop
  • 合併到分支:develop
  • 分支命名約定:feature-*

功能分支,在開發某一個新功能時,從 develop 分支分出來,開發完之後,再合併回 develop 分支。

功能分支通常只存在於開發者的本地倉庫中,並不包含在遠程庫中。

創建一個功能分支:

git checkout -b feature-x develop

開發完成後,將功能分支合併到 develop 分支:

git checkout develop

git merge --no-ff feature-x

刪除 feature 分支:

git branch -d feature-x

release

  • 分支來源:develop
  • 合併到分支:develop,master
  • 分支命名約定:release-*

預發佈分支,它是指發佈正式版本之前,我們可能需要有一個預發佈的版本測試,並且可以在上面做一些較小 bug 的修復。

預發佈分支是從 develop 分支上分出來的,預發佈結束以後,必須合併進 develop 和 master 分支。

創建一個預發佈分支:

git checkout -b release-1.2 develop

確認沒有問題後,合併到 master 分支:

git checkout master

git merge --no-ff release-1.2

# 對合並生成的新節點,做一個標籤
git tag -a 1.2

再合併到 develop 分支:

git checkout develop

git merge --no-ff release-1.2

最後,刪除預發佈分支:

git branch -d release-1.2

hotfix

  • 分支來源:master
  • 合併到分支:develop,master
  • 分支命名約定:hotfix-*

最後一種是修復 bug 分支。軟件正式發佈以後,難免會出現 bug。這時就需要創建一個分支,進行 bug 修復。

修復 bug 分支是從 master 分支上分出來的。修復結束以後,再合併進 master 和 develop 分支。

創建一個修復 bug 分支:

git checkout -b hotfix-0.1 master

修復結束後,合併到 master 分支:

git checkout master

git merge --no-ff hotfix-0.1

git tag -a 0.1.1

再合併到 develop 分支:

git checkout develop

git merge --no-ff hotfix-0.1

最後,刪除修復 bug 分支:

git branch -d hotfix-0.1

小結

優點:

  1. 各分支權責分明,清晰可控,是很多分支管理策略的啓蒙模型。

缺點:

  1. 合併衝突:同時長期存在的分支可能會很多:master、develop、release、hotfix、若干並行的 feature 分支。兩兩之間都有可能發生衝突。頻繁手動解決衝突不僅增加工作量,而且增大了出錯的風險。
  2. 功能分離:功能並行開發時,合併分支前無法測試組合功能,而且合併後可能會出現互相影響。
  3. 無法持續交付:Git flow 更傾向於按計劃發佈,一個 feature 要經歷很多步驟才能發佈到正式環境,難以達到持續交付的要求。
  4. 無法持續集成:持續集成鼓勵更加頻繁的代碼集成和交互,儘早解決衝突,而 Git flow 的分支策略隔離了代碼,儘可能推遲代碼集成。

Github flow

Github flow 是一個輕量級的基於分支的工作流程。它由 GitHub 在 2011 年創建。分支是 Git 中的核心概念,並且 GitHub 工作流程中的一切都以此爲基礎。

它只有一個長期分支 master,其他分支都在其基礎上創建。使用流程如下:

  1. 根據需求,從 master 拉出新分支,不用區分功能分支或修復分支,但需要給出描述性的名稱。
  2. 本地的修改直接提交到該分支,並定期將其推送到遠程庫上的同一命名分支。
  3. 新分支開發完成後,或者需要討論的時候,向 master 發起一個 Pull Request(簡稱 PR)。
  4. Pull Request 既是一個通知,讓別人注意到你的請求,又是一種對話機制,大家一起評審和討論你的代碼。對話過程中,你還可以不斷提交代碼。
  5. 你的 Pull Request 被接受,合併進 master,重新部署後,原來你拉出來的那個分支就被刪除了。

小結:

優點:

  1. 降低了分支管理複雜度,更適合小型團隊,或者維護單個版本的項目開發。
  2. 工作流程簡單,對持續交付和持續集成友好。

缺點:

  1. 無法支持多版本代碼部署。

Gitlab flow

它是 Git flow 與 Github flow 的綜合。吸取了兩者的優點,既有適應不同開發環境的彈性,又有單一主分支的簡單和便利。

Gitlab flow 和 Github flow 之間的最大區別是 Gitlab flow 支持環境分支。

Gitlab flow 的最大原則叫做"上游優先"(upsteam first),即只存在一個主分支 master,它是所有其他分支的"上游"。只有上游分支採納的代碼變化,才能應用到其他分支。

Gitlab flow 分成兩種情形來應付不同的開發流程:

  • 持續發佈
  • 版本發佈

持續發佈

對於持續發佈的項目,它建議在 master 分支以外,再建立不同的環境分支,每個環境都有對應的分支。比如,開發環境的分支是 master,預發環境的分支是 pre-production,生產環境的分支是 production。

  • 開發分支 master 用於發佈到測試環境,該分支爲受保護的分支。
  • 預發分支 pre-production 用於發佈到預發環境,上游分支爲 master。
  • 正式分支 production 用於發佈到正式環境,上游分支爲 pre-production。

如果生產環境(production)發生錯誤,則要建一個新分支修改完後合併到最上游的開發分支(master)此時就是(Upstream first),且經過測試,再繼續往 pre-production 合併,要經過測試沒有問題了才能夠再往下合併到生產環境。

版本發佈

對於版本發佈的項目,建議的做法是每一個穩定版本,都要從 master 分支拉出一個分支,比如 2-3-stable、2-4-stable 等。

在出現 bug 後,根據對應的 release branch 創建一個修復分支,修復工作完成後,一樣要按照上游優選的原則,先合併到 master 分支,經過測試才能夠合併到 release 分支,並且此時要更新小版本號。

小結

優點:

  1. 可以區分不同的環境部署。
  2. 對持續交付和持續集成友好。

缺點:

  1. 分支多,流程管理複雜。

TrunkBased

Trunk Based Development,又叫主幹開發。開發人員之間通過約定,向被指定爲主幹,一般爲 master,的分支提交代碼,以此來抵抗因爲長期存在的多分支導致的開發壓力。這樣可以避免分支合併的困擾,保證隨時擁有可發佈的版本。

使用主幹開發後,只有一個 master 分支了,所有新功能也都提交到 master 分支上,保證每次提交後 master 分支都是可隨時發佈的狀態。

沒有了分支的代碼隔離,測試和解決衝突都變得簡單,持續集成也變得穩定了許多,但也有如下幾個問題:

  • 如何避免發佈的時候引入未完成的 feature
  • 如何進行線上 bug fix

如何避免發佈的時候引入未完成的 feature

答案是:Feature Toggle

既然代碼要隨時保持可發佈,而我們又需要只有一份代碼來支持持續集成,在代碼庫里加一個特性開關來隨時打開和關閉新特性是最容易想到的,當然也是最容易被質疑的解決方案。

Feature Toggle 是有成本的,不管是在加 Toggle 的時候的代碼設計,還是在移除 Toggle 時的人力成本和風險,都是需要和它帶來的價值進行衡量的。

事實上,在我們做一個前端的大特性變更的時候,我們確實因爲沒辦法 Toggle 而採用了一個獨立的 feature 分支,我們認爲即使爲了這個分支單獨做一套 Pipeline,也比在前端的各種樣式間添加移除 Toggle 來得簡單。

但同時,團隊商議決定在每次提交前都要先將 master 分支合併到 feature 分支,以此避免分支隔離久以後合併時的痛苦。

如何進行線上 bug fix

在發佈時打上 release tag,一旦發現這個版本有問題,如果這個時候 master 分支上沒有其他提交,可以直接在 master 分支上 hot fix,如果 master 分支已經有了提交就要做以下四件事:

  1. 從 release tag 創建發佈分支。
  2. 在 master 上做 bug fix 提交。
  3. 將 bug fix 提交 cherry-pick 到 release 分支。
  4. 在 release 分支再做一次發佈。

線上 fix 通常都比較緊急。看完這個略顯繁瑣的 bug fix 流程,你可能會問爲什麼不在 release 分支直接 fix,再合併到 master 分支?

這樣做確實比較符合直覺,但事實是,如果在 release 分支做 fix,很可能會忘了合併回 master。

試想深夜兩點你做完 bug fix 眼看終於上線成功,這時你的第一反應就是“終於可以下班了。什麼,合併回 master? 明天再來吧“

等到第二天你早已把這個事忘得一乾二淨。而問題要等到下一次上線纔會被暴露出來,一旦發現,而這個時候上一次 release 的人又不在,無疑增加了很多工作量。

總結

以上四種就是目前相對主流的分支管理策略,但沒有哪一種策略是萬能的。所以無論選擇哪一種,都需要考慮團隊的實際情況,以及項目的具體業務需求,適合自己的纔是最好的。

最後,再分享三點小建議:

  1. 臨時分支不應該存在太久,每個分支應儘量保持精簡,用完即刪
  2. 工作流應該儘量簡單,同時方便回滾
  3. 工作流程應該符合我們的項目發佈計劃

以上就是本文的全部內容,如果覺得還不錯的話歡迎點贊轉發關注,感謝支持。


參考文章:

擴展閱讀:

推薦閱讀:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章