GitHub Flow & Git Flow 基於Git 的兩種協作開發模式
01、分支模型

- master:長期分支,一般用於管理對外發布版本,每個 commit 對一個 tag,也就是一個發布版本
- develop:長期分支,一般用於作為日常開發匯總,即開發版的代碼
- feature: 短期分支,一般用於一個新功能的開發
- hotfix :短期分支 ,一般用於正式發布以后,出現 bug,需要創建一個分支,進行 bug 修補。
- release :短期分支,一般用於發布正式版本之前(即合並到 master 分支之前),需要有的預發布的版本進行測試。
master和develop作為主要分支。
新功能的開發在feature上進行,該分支從develop分支派生,功能開發完畢后merge到develop分支。 一般feature分支都存在與開發者本地,除非該分支需要多方合作才提交到遠程倉庫。
如何保證和develop分支的代碼同步?每天從develop分支拉去最新的代碼,使用rebase命令 不要使用pull,每次合並上游更改時feature 分支都會引入一個外來的合並提交,使用pull會生成一個新的合並commit。
在將其他分支的代碼合並到當前分支時,如果那個分支是當前分支的父分支,為了保持圖表的可讀性和可追蹤性,可以考慮用 git rebase 來代替 git merge;反過來或者不是父子關系的兩個分支以及互相已經 git merge 過的分支,就不要采用 git rebase 了,避免出現重復的沖突和提交節點。
release分支是從develop分支派生, bug fix只在release分支上進行,該分支也是QA的測試分支,開發結束后同時合並進develop和master分支
使用merge request將release分支的提交合並master分支,並打上tag。
hotfix可以單獨出一個分支,也可以直接在release分支上進行。
所有master上的代碼都是從release分支合並進去的。
追蹤遠程develop分支
git checkout -b develop origin/develop
feature 分支操作
獲取dev分支最新代碼
$ git pull --rebase origin dev 或者 $ git rebase dev $ git checkout -b myfeature develop $ git checkout develop Switched to branch 'develop' $ git merge --no-ff myfeature Updating ea1b82a..05e9557 (Summary of changes) $ git branch -d myfeature Deleted branch myfeature (was 05e9557). $ git push origin develop
rebase最大的好處是你的項目歷史會非常整潔。首先,它不像git merge 那樣引入不必要的合並提交。其次,如上圖所示,rebase導致最后的項目歷史呈現出完美的線性——你可以從項目終點到起點瀏覽而不需要任何的Fork。這讓你更容易使用git log 、git bisect 和gitk 來查看項目歷史。 不過,這種簡單的提交歷史會帶來兩個后果:安全性和可跟蹤性。如果你違反了Rebase黃金法則,重寫項目歷史可能會給你的協作工作流帶來災難性的影響。此外,rebase不會有合並提交中附帶的信息——你看不到feature分支中並入了上游的哪些更改。
rebase的黃金法則
git rebase 的黃金法則便是,絕不要在公共的分支上使用它。 比如說,如果你把master分支rebase到你的feature分支上會發生什么
場景:你在feature上開發了一些功能還沒有能夠提交,現在有個Bug需要在develop分支上fix,怎么操作?
在feature分支上 執行 add & stash ,將當前的更新暫存起來
切換到develop分支,fix bug,commit & push(也可以不push)
切換到feature分支,rebase develop分支,發現沖突就解決沖突
最后 git stash pop ,彈出之前暫存的內容,這時也可能發生沖突,也比較好解決
這里主要就是應用了stash的功能,防止在feature上開發的功能還未能夠提交,同時又有緊急的bug需要fix。
release 分支操作
# 合並到master $ git checkout master Switched to branch 'master' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes) $ git tag -a 1.2 # 合並到develop $ git checkout develop Switched to branch 'develop' $ git merge --no-ff release-1.2 # 刪除release分支 $ git branch -d release-1.2
hotfix 分支操作
當產品發布出去之后,有緊急的bug,就需要從master分支中拉出一個hot fix分支。 這么做的好處是develop分支上的同事可以繼續進行開發,另一個團隊則可以在master分支上進行一個產品修復更新。 修復好之后,合並到mater分支和develop分支。
這里有一個特殊情況,如果當時的release分支還存在,那么hotfix的更新需要merge到相應的release分支上。 如果release分支已經不存在了,那么就只需要merge到master分支和develop分支。
創建遠程分支
git push origin local_branch:remote_branch
local_branch必須為你本地存在的分支,remote_branch為遠程分支,如果remote_branch不存在則會自動創建分支。
02、開發規范
commit規范
只要堅持做到以下幾點就 OK 了:
- 提交時的粒度是一個小功能點或者一個 bug fix,這樣進行恢復等的操作時能夠將「誤傷」減到最低;
- 用一句簡練的話寫在第一行,然后空一行稍微詳細闡述該提交所增加或修改的地方;
- 不要每提交一次就推送一次,多積攢幾個提交后一次性推送,這樣可以避免在進行一次提交后發現代碼中還有小錯誤。
誰說歷史不可篡改了?前提是,想要合並的那幾次提交還沒有推送到遠程!
Commit Message 格式
<type>(<scope>): <subject> <空行> <body> <空行> <footer>
type
- feat:新功能(feature)
- fix:修補bug
- docs:文檔(documentation)
- style: 格式(不影響代碼運行的變動)
- refactor:重構(即不是新增功能,也不是修改bug的代碼變動)
- test:增加測試
- chore:構建過程或輔助工具的變動
Scope
用來說明本次Commit影響的范圍,即簡要說明修改會涉及的部分。這個本來是選填項,但從AngularJS實際項目中可以看出基本上也成了必填項了。
Subject
用來簡要描述本次改動,概述就好了,因為后面還會在Body里給出具體信息。並且最好遵循下面三條:
- 以動詞開頭,使用第一人稱現在時,比如change,而不是changed或changes
- 首字母不要大寫
- 結尾不用句號(.)
Body
<body>里的內容是對上面subject里內容的展開,在此做更加詳盡的描述,內容里應該包含修改動機和修改前后的對比。
Footer
footer里的主要放置不兼容變更和Issue關閉的信息
Revert
此外如果需要撤銷之前的Commit,那么本次Commit Message中必須以revert:開頭,后面緊跟前面描述的Header部分,格式不變。並且,Body部分的格式也是固定的,必須要記錄撤銷前Commit的SHA值。
提交
推送
拉取
1. 把本地repo從上次pull之后的變更暫存起來
2. 恢復到上次pull時的情況
3. 套用遠端的變更
4. 最后再套用剛暫存下來的本地變更
有沖突怎么辦?
rebase跟merge類似,出現conflict會暫停rebase動作,需要你手動修復后,然后才可以繼續動作。這也是rebase比merge復雜一點的地方:merge如果發生conflict,你只需要解決沖突一次,然后commit出去就完成了。而rebase的conflict可能會發生在上述步驟4的每一次重新套用上,所以可能需要解決沖突好幾次。
到底什么時候用merge?什么時候用rebase?
如果你修改比較多,預期會有較多的conflict,建議用merge。(不過,如果是多次大范圍的主題式修改,那是不是應該一開始就多開一個branch來做呢?)。
如果改動范圍較小,不太預期有conflict,則建議可以加上rebase參數。
如果想要把 rebase 當做 git pull 的預設值,可以在專案的 .git/config 加上
[branch "master"]
remote = origin
merge = refs/heads/master
rebase = true
也可以直接加到 ~/.gitconfig 讓所有的 tracked branches 都自動套用這個設定:
[branch]
autosetuprebase = always
合並
在將其他分支的代碼合並到當前分支時,如果那個分支是當前分支的父分支,為了保持圖表的可讀性和可追蹤性,可以考慮用 git rebase 來代替 git merge;反過來或者不是父子關系的兩個分支以及互相已經 git merge 過的分支,就不要采用 git rebase 了,避免出現重復的沖突和提交節點。
分支命名
除了主要分支的名字是固定的之外,派生分支是需要自己命名的,這里就要有個命名規范了。強烈推薦用如下形式:feature——按照功能點(而不是需求)命名;
release——用發布時間命名,可以加上適當的前綴;
hotfix——GitLab 的 issue 編號或 bug 性質等。
另外還有 tag,用語義化的版本號命名。
