參考資料
簡介
規(guī)范的分支管理策略可以使得版本庫的演進保持簡潔,主干清晰,各個分支各司其職、井井有條。

常駐分支
整個版本庫中應(yīng)該有兩個一直演進的常駐分支,分別是 master 和 develop。
master
主分支上的代碼提交都是處于可發(fā)布狀態(tài)的,是所有提供給用戶使用的正式版本。我們使用版本庫初始化時默認創(chuàng)建的 master 分支。
develop
主分支只用來發(fā)布版本,日常的工作都應(yīng)該提交到開發(fā)用的 develop 分支。該分支 HEAD 源碼始終體現(xiàn)下個發(fā)布版的最新軟件變更。當 develop 分支的源碼到達了一個穩(wěn)定待發(fā)布狀態(tài)時,就可以合并到 master 分支中。
輔助分支
除了常駐分支外,開發(fā)流程中還需要各種輔助性分支,用來支持團隊成員們并行開發(fā),使功能易于追蹤,協(xié)助生產(chǎn)發(fā)布環(huán)境準備,以及快速修復(fù)實時在線問題。與常駐分支不同,輔助分支的生命期是有限的,當它們的提交被合并到常駐分支后,就會被移除。輔助分支包括:feature、fix、release 和 hotfix。
feature
feature 分支從 develop 分支分出,為了實現(xiàn)某個特定的功能,并最終合并到
develop 分支中。
fix
fix 分支從 develop 分支分出,為了修復(fù)測試過程中發(fā)現(xiàn)的某個 bug ,并最終合并到 develop 分支中。
release
在 develop 分支達到了發(fā)布的理想狀態(tài)時,就分出一個 release 分支。release 分支是為新版本的發(fā)布做準備的,它允許我們在最后時刻做一些細小的修改,如一些 bug 的修改和準備發(fā)布元數(shù)據(jù)(版本號等)。在確定發(fā)布后,就將 release 分支合并到 master 分支和 develop 分支,并移除 release 分支。
hotfix
hotfix 分支與 release 分支相似,他們都為新的生產(chǎn)環(huán)境發(fā)布做準備,盡管這是未經(jīng)計劃的。當生產(chǎn)環(huán)境發(fā)現(xiàn) bug 且必須馬上修復(fù)時,從 master 分支分出 hotfix 分支,在修復(fù)提交后,將 hotfix 分支合并到 master 分支和 develop 分支,并移除 hotfix 分支。
工作流程
開發(fā)人員通過 issue 列表獲取新功能開發(fā)任務(wù),然后從 develop 分支分出 feature_[issue number] 分支,在新功能開發(fā)完成后,將 feature_[issue number] 分支合并到 develop 分支,并將其移除。
git checkout -b feature_[issue number] develop
git checkout develop
git merge --no-ff feature_[issue number]
git branch -d feature_[issue number]
在新功能被測試后,開發(fā)人員通過 issue 列表獲取修復(fù) bug 的任務(wù),然后從 develop 分支分出 fix_[issue number] 分支,在修復(fù)工作完成后,將 fix_[issue number] 分支合并到 develop 分支,并將其移除。
git checkout -b fix_[issue number] develop
git checkout develop
git merge --no-ff fix_[issue number]
git branch -d fix_[issue number]
待新功能穩(wěn)定將要發(fā)布時,從 develop 分支分出 release_[version number] 分支,version number 是將要發(fā)布的版本號,在確定 release_[version number] 分支上不會有其他改動后,就可以將其合并到 develop 分支和 master 分支,并移除。在 master 分支的新提交點上添加版本號 tag。
git checkout -b release_[version number] develop
git checkout master
git merge --no-ff release_[version number]
git tag -a v[version number]
git checkout develop
git merge --no-ff release_[version number]
git branch -d release_[version number]
如果生產(chǎn)環(huán)境發(fā)現(xiàn) bug 且必須馬上修復(fù)時,從 master 分支分出 hotfix_[version number] 分支,在修復(fù)提交后,將 hotfix_[version number] 分支合并到 master 分支和 develop 分支,并移除 hotfix_[version number] 分支。在 master 分支的新提交點上添加版本號 tag。
git checkout -b hotfix_[version number] master
git checkout master
git merge --no-ff hotfix_[version number]
git tag -a v[version number]
git checkout develop
git merge --no-ff hotfix_[version number]
git branch -d hotfix_[version number]
關(guān)于 merge 命令中的--no-ff參數(shù),即使該操作可以快進式合并(fast-farward),但仍然會采用正常合并,在分支上生成一個新的節(jié)點。這樣就不會丟失輔助分支的歷史信息,保證了版本演進的清晰。

團隊協(xié)作開發(fā)
大部分的軟件開發(fā)工作都不是由一個人獨立完成的,而是需要一個團隊協(xié)作完成。一般我們需要在服務(wù)器端搭建一個中心代碼庫,而團隊中的成員都是通過本地代碼庫不斷的和中心代碼庫之間實現(xiàn)拉取和推送代碼的操作來協(xié)作完成任務(wù)的。
中心代碼庫可能只存在 master 和 develop 兩條常駐分支。其他的輔助分支,開發(fā)人員可以在任務(wù)完成后,先并入本地的常駐分支,之后再推送到中心代碼庫來同步更新。向中心代碼庫提交代碼時要注意的一點是,一定要將本地的提交 rebase 到服務(wù)器端最新的提交之后再推送代碼,這樣可以避免不必要的合并分支節(jié)點,使演進歷史更清晰。
一般團隊中都會通過代碼審查來提高整個軟件的代碼健壯性。這時,完成任務(wù)的開發(fā)者不能自己將輔助分支合并入常駐分支,而要由審查人員在通過后將其并入。審查代碼的開發(fā)者可以直接從完成任務(wù)的開發(fā)者的本地版本庫拉取分支,也可以通過讓完成任務(wù)的開發(fā)者將分支提交到中心代碼庫來獲取,但要在并入常駐分支后,將中心代碼庫中的輔助分支刪除。
為了使代碼提交歷史更加清晰,可進一步規(guī)范,將任務(wù)單元劃分的盡量小,即每一個輔助分支最終在并入常駐分支時都只有一次提交。開發(fā)人員在完成任務(wù)前,可根據(jù)需要執(zhí)行多次提交,但在合并入常駐分支時,要通過rebase -i命令將提交變?yōu)橐淮?。同時要對提交信息的格式規(guī)范化,如:
[功能輔助分支名][模塊名]:簡短的描述信息[issue number]
在提交信息格式化后,每次將輔助分支合并入常駐分支時,不需要使用--no-ff參數(shù),因為提交信息完全可以說明輔助分支的歷史,在去掉這些空的合并節(jié)點后,會使提交歷史更加簡潔清晰。
2020.02.10 更新:關(guān)于 iOS 項目分支管理的想法
當前工作中,iOS 應(yīng)用發(fā)布新版本的方式與 web 開發(fā)不同,需要通過 Xcode 手動歸檔,然后向 App store 提交,待審核通過后,才算是發(fā)版成功。在這種情況下,無法利用鉤子自動發(fā)布 master 分支上的代碼,那么其存在的意義就不大了,考慮僅維護 develop 一個常駐分支。develop 分支保持著程序的最新可用狀態(tài),當一部分開發(fā)工作完成后,develop 分支上的某次提交會作為對外發(fā)布的版本。當然,需要人為控制的一點是,必須注意并入的提交的順序,不能讓下一版本的提交在本次版本的提交之前并入,否則就會把下一版本的內(nèi)容提前發(fā)布出去了。
當確定了要發(fā)版的提交后,假設(shè)發(fā)版的相關(guān)提交、可能出現(xiàn)的緊急修復(fù)的提交、下一版本的需求提交是按先后順序操作的,那么僅需要 develop 分支就夠了,在對應(yīng)的提交打版本標簽即可。但現(xiàn)實中,很多時候情況并不是這樣的,發(fā)版的操作可能有一定的延后性,而需要緊急修復(fù)的 bug 的出現(xiàn),更是具有不確定性。在確定了要發(fā)版的提交后,后續(xù)的工作會繼續(xù)進行,下一版本的需求提交就會開始并入 develop 分支中,正是因為這樣,所以發(fā)版的提交或緊急修復(fù)的提交就不能直接并入 develop 分支了,這會導(dǎo)致將下一版本的部分提交提前發(fā)布出去。
當發(fā)版時,我們需要在發(fā)版提交上新建 release 輔助分支,之后發(fā)版的相關(guān)提交在該分支上操作,發(fā)布新版本后將 release 分支上新的提交并入到 develop 分支上,之后即可刪除 release 分支,而版本標簽就應(yīng)該打在 release 分支的最后一次提交上。iOS 開發(fā)因為審核的問題,在將 release 分支的最新提交打包到 App store 審核時,發(fā)版工作并沒有完成,還不能將 release 分支并入 develop 分支。假如審核未通過,需要修改代碼,則在 release 分支上繼續(xù)進行提交,因為這還是對同一個版本的發(fā)布,直到審核通過后,將 release 分支的提交并入 develop 分支。如果并入 release 分支時,develop 分支上沒有下一版本的提交,那么快進式合并則會使 release 分支的提交像需求提交一樣直接在開發(fā)分支的直線上,但為了與不能快進合并的情況以及可能的緊急修復(fù)的情況統(tǒng)一,并且可以更醒目地標出發(fā)布的版本,合并時使用--no-ff參數(shù),強制創(chuàng)建新的提交。
對于緊急修復(fù)的操作,如果主分支上沒有下一版本的提交,那么緊急修復(fù)完全可以當做下一個版本來操作(因為 iOS 改動一定要提交新版本)。而如果已經(jīng)有了下一版本的提交,則應(yīng)該在當前版本對應(yīng)的提交(release 分支上的最后一次提交)上新建 hotfix 輔助分支,然后在該分支上提交修復(fù) bug 、修改發(fā)版信息、可能的對審核未通過的修改。待針對緊急修復(fù)的新版本上架后,將 hotfix 分支并入 develop 分支中,之后即可刪除 hotfix 分支,版本標簽應(yīng)該打在 hotfix 分支的最后一次提交上。