http://ihower.tw/blog/archives/5140/
Update: 2011/3/19 受邀有場分享 Git介紹,使用與開發流程 at Facebook 軟體開發團隊工具心得分享
大家都知道 Git 開 branch 很方便,非常鼓勵 topic branch,但有沒有一套模型流程告訴我們應該怎麼管理 branch 呢? 有人便整理出一套最佳實踐慣例 A successful Git branching model,我們團隊就採用了這套流程。簡單來說,他將 branch 分成兩個主要分支,三種支援性分支:
- 主要分支
- master: 永遠處在 production-ready 狀態
- develop: 最新的下次發佈開發狀態
- 支援性分支
- Feature branches: 開發新功能都從 develop 分支出來,完成後 merge 回 develop
- Release branches: 準備要 release 的版本,只修 bugs。從 develop 分支出來,完成後 merge 回 master 和 develop
- Hotfix branches: 等不及 release 版本就必須馬上修 master 趕上線的情況。會從 master 分支出來,完成後 merge 回 master 和 develop
作者還提供了 git-flow 指令工具幫助我們很容易的實踐,用法如下:
首先是初始化動作:
git flow init
初始化動作會問你一些問題,大抵是命名慣例:
No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]
How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []
設定完之後,預設的 branch 就變成 develop 了。有任何開發,一律都先開 branch:
git flow feature start some_awesome_feature
(以此類推 git flow release 和 git flow hotfix)
完成之後輸入
git flow feature finish some_awesome_feature
就會合併回 develop 並幫你刪除這個 (local) branch。
關於 REMOTE BRANCH
這個 git-flow 工具並沒有幫我們處理 remote branch,所以如果你的 branch 要 push 出去分享給別人,就要自己打 git 指令啦 同事留言說有支援啦:
push 一個 feature branch 到遠端:
git flow feature publish some_awesome_feature
或 git push origin feature/some_awesome_feature
追蹤一個遠端的 branch:
git flow feature track some_awesome_feature
或 git checkout -b feature/some_awesome_feature -t origin/feature/some_awesome_feature
刪除遠端的 branch:
git push origin :feature/some_awesome_feature
我們還碰到一個問題是輸入 git flow feature finish 時出現以下錯誤:
warning: not deleting branch 'feature/some_awesome_feature' that is not yet merged to
'refs/remotes/origin/feature/some_awesome_feature', even though it is merged to HEAD.
error: The branch 'feature/some_awesome_feature' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature/some_awesome_feature'.
原因是這個 feature branch 一開始是從遠端 checkout 出來的,以及這個 feature branch 有 commit 沒有 push 回去 ,所以 git flow 不敢幫你刪除 local branch,這時候其實 merge 動作已經完成了,所以你可以手動輸入 git branch -D feature/some_awesome_feature 強制刪除 local branch 即可。(小結論:git-flow 只是個輔助工具,了解 git 還是必要的)
關於 FEATURE BRANCH 的合併
如果是開發時間比較久的 feature branch,很可能會因為 1. 不定時的 merge develop 與新版同步 2. 實驗性質的修改 3. 需求的變更 等等因素,而讓這個 feature branch 的 commit 記錄變成髒髒的,這時候我們會用以下的方式來做 merge 動作:
1. 先對 feature branch 做 `git rebase develop`。會很苦,但是弄完會很有成就感,整個 branch commit history 會變成很乾淨。請學 interactive mode,可以讓你拿掉一些 commit、合併或修改,你也可以 rebase 多次直到滿意為止。
2. 在從 develop bracnh 做 `git merge feature/some_awesome_feature –no-ff`,–no-ff 的意思是會強制留一個 merge commit log 記錄,這可以讓 commit tree 看清楚發生了 merge 動作。(因為我們剛做了 rebase,而 git 預設的合併模式是 fast-forward,所以如果不加 –no-ff 是不會有 merge commit 的) 這個 merge commit 的另一個額外方便之處是,如果想要 reset/revert 整個 branch 只要 reset/revert 這個 commit 就可以了。
3. 如果此 feature branch 有 remote branch,要先砍掉 `git push origin :feature/some_awesome_feature` 再 `git push origin develop` (這是因為 rebase 一個已經 push 出去的 repository,然後又把修改的 history push 出去,會造成超級大災難啊~)
先 rebase 再 merge –no-ff 這樣做的好處到底是什麼? 看圖體會一下吧:
每一次的 merge 就代表了一個 feature 完成,也可以很清楚看到這個 feature branch 底下包含哪些 commit。
對了,如果有用 Github 的話,請記得務必用一用它的 pull request 功能,我們會在 branch 完成後發一個 pull request,好讓大家可以對一整個 branch 做 code review 留言。
註:什麼是 rebase 可以參考舊作: Git 版本控制系統(3) 還沒 push 前可以做的事