在上一篇 part 1 中指出了 gitflow 帶來的不方便,這篇文章會介紹目前團隊採用的方式,原則很簡單—所有的新增及修正都基於 master 分支。
在開始以前,你必須對 git 有基本的了解,包括 (no-)fast-forward merge 及 rebase 的觀念。
最單純的情況(無環境因素)
假設沒有開發環境的需求,所以移除了 develop 分支。
A
是上一次出版的 commit,可以看到所有分支(feature/release/hotfix)都是由此 commit 出發。
# 每次產生新 branch 之前
git checkout master
# features
git checkout -b feature/1
git checkout -b feature/2
# release
git checkout -b release/v0.1.0
# hotfix
git checkout -b hotfix/v0.0.1
在兩個 feature branch 開發差不多之後,merge 進 release
git checkout release/v0.1.0
git merge feature/1
git merge feature/2
修正或確認沒有 bug 之後,merge 回去 master 加上 tag 完成這次開發流程。
git checkout master
git merge release/v0.1.0
git tag -a v0.1.0
從 A
到 A'
也可以看出,整個開發流程是一個完整的循環。
如何處理 hotfix
在正式環境或版本出現緊急要修正的東西就會 hotfix,對開發流程來說,就表示 master 變了,這時候根據目前開發的狀況可以有三種選擇:
- 如果你本地端有開發中的 feature 分支,可以 rebase 到
C
,可以想成A
被C
取代,然後繼續流程。
git checkout feature
git rebase master
- 如果 feature 分支已經上到遠端或在進行 code review 了,就不太適合 rebase(因為整個分支的 commit 會 rewrite),這時要 merge
master
。
git checkout feature
git merge master
- 如果已經作出了 release 分支就可以直接把 master merge 進去。
git checkout release
git merge master
處理相依性
現在的情況是如果這次的出版週期有一個功能 feature/3,而同一出版週期的 feature/1 及 feature/2 都需要它的功能。
一個作法可以把兩個分支都 rebase 到 feature/3。但我比較推薦用 merge,有兩個好處:
- 不會 rewrite commit,
- 如果最後你不想要 feature/3 也比較容易 revert。
merge 的結果如下圖。
A
會有 feature/2 及 feature/3,而 B
會有全部三個分支的功能;這樣也表示說無論你只出版 feature/1 或者 feature/2,都會有 feature/3 的內容。
上面是各個 feature 分別都 merge feature/3,有人會問說怎麼 feature/3 不直接進去 release 就好?我是覺得在每個 feature 分支都可以看到該功能相關的 commit 會比較明確,但相對的比較繁瑣,直接進去 release 看整合效果的作法當然也可以,所以可以依情況作調整。
有開發環境的情況
這邊加入了 develop 分支
develop 對應到 test 環境(如 A
),release 對應到 staging 環境。
完成出版後,develop 可以 merge master
git checkout develop
git merge master
這邊可以發現它會 fast forward,如 B
。
ps. 發現很多人不懂 fast forward 是什麼意思,請一定要先了解它
實務中會發生的情況
上面講的只是理想,現實中的開發尤其是用戶端的應用程式,很常出現一種情況 — 已經進到 develop 的 feature 沒有要出版 🙄🙄🙄。
下面圖表所表示的情況是:在此開發週期中同時開發了 feature/1 及 /2,並已經在 test 環境上讓 QA 驗證上述兩個功能。接著要出版本時,PM 說 feature 2 先不要上,因此只發表 feature 1。
A
這點同時有 feature 1 跟 2,並且在 test 環境上。
B
只 merge 了 feature/1,會部屬到 staging 環境讓 QA 驗證後出版。
這邊有一件事要提醒:在 A
驗證沒問題,並不表示 B
沒問題,因為 B
沒有 feature/2 的東西,所以即使 test 環境驗證 ok,出版前仍必須在 staging 驗證一次。
好,接下來的問題就只剩下怎麼處理 develop 和 feature/2 這兩個分支。
圖中實色的部份是 develop 目前的內容。有 feature/1 及 feature/2,feauture/1 已經出版了就不討論。
(2018/4/20 更新,原本的想法是直接重新從 master 開一個 develop 分支,再強制覆寫回 origin,理由是 develop 只對應到 CI,因此是可拋棄的。但後來想想,推到 remote 的分支不應該任意覆寫,因此還是保留 develop 的歷史比較恰當。)
develop 及未出版的 feauture/2 都需要 master 中的內容,因此他們分別 merge master 即可。要注意因為 feature/2 可能會新增內容並 merge 進去 develop,因此不可以 rebase master。
如果你堅持要用 develop 來開發
當然也可以。但有個前提,你不能再把 develop 對應到 CI 的測試環境,要取另一個名稱,下圖中該分支是命名為 test-env。
從這個圖表可以看出幾件事:
- 除了 hotfix 之外其餘分支都由 develop 建立
- tag 仍然作在 master 上面
- master 會是 develop 的前一個 commit,而且絕對可以 fast-forward
因為 hotfix 仍然從 master 產生而不是 develop,這表示因為堅持 develop 這個分支名稱必須多加這一項常規,個人認為是多此一舉。可行但不推薦。
結語
從上面的介紹,可以看出,即使規範了一套常規,在很多時候,還是有需要因應現實情況作調整的地方:
- 在 hotfix 或處理相依性時,可以選擇用 rebase 或者 merge
- 要不要保留對應到測試環境的分支的歷史
- 整個開發建構在其之上的基礎分支要不要命名為 master
所以一切都是團隊的選擇,沒有對錯也沒有一定要怎麼作。
這篇文章我盡量列出了會遇到的情境和可能的應對方法,給大家參考。如果有什麼部分是我沒有思考到的,也歡迎跟我反應。
Happy coding!