專案中的 Git 使用規範

Taylor發表於2020-04-09

0. 我們可能面臨的問題


試想遇到以下這些問題,會採取怎樣的方式去解決:
* 需要線上某個歷史版本的原始碼,直接在 develop 分支根據提交記錄和時間找對應的節點?
* 線上版本出現嚴重 bug 需要緊急修復發版本,而你的專案就一個分支,上個版本釋出之後已經有大量改動了,怎麼辦?
* 某個提交改動了部分程式碼,涉及到 10 幾個檔案,現在這個改動不需要了,此時要一個個找出這些檔案然後再改回去麼?
* 出現了一個 bug,之前好像處理過,但是現在忘了當初怎麼處理的了,在一堆寫著 “fix bug”、“update” 的提交記錄中,如何找到當初那筆的提交?
* 某個功能本來準備釋出的,現在突然決定這個版本不上了,現在要一處處找到之前的程式碼,然後再改回去?
* ……
以上這些問題在我們的專案中都是會或多或少出現的,部分問題可能涉及到的是對 Git 的功能是否熟悉的問題,大部分問題則是涉及到一個專案的 Git 使用規範問題,如果有一個很好的規範,在專案中合理地使用 Git,很多問題壓根就不是問題。

1. Git 規範的必要性


1. 分支管理

* 程式碼提交在應該提交的分支
* 隨時可以切換到線上穩定版本程式碼
* 多個版本的開發工作同時進行

2. 提交記錄的可讀性

* 準確的提交描述,具備可檢索性
* 合理的提交範圍,避免一個功能就一筆提交
* 分支間的合併保有提交歷史,且合併後結果清晰明瞭
* 避免出現過多的分叉

3. 團隊協作

* 明確每個分支的功用,做到對應的分支執行對應的操作
* 合理的提交,每次提交有明確的改動範圍和規範的提交資訊
* 使用 Git 管理版本迭代、緊急線上 bug fix、功能開發等任務

以上就是一份 Git 規範的作用和使命。
接下來結合 Git-Flow ,總結了一份專案中使用 Git 的規範。
[image:BB1098EB-486A-4940-872A-D4A3568778FA-30333-00010D3D39F4E7C8/git-flow.png]

2. 分支管理規範


2.1 分支說明和操作

  • $sub-master 分支
    • 主分支,永遠處於隱藏狀態,對應當前線上版本。
    • 以 tag 標記一個版本,因此在 master 分支上看到的每一個 tag 都應該對應一個線上版本。
    • 不允許在該分支直接提交程式碼。
  • $sub-develop 分支
    • 開發分支,包含了專案最新的功能和程式碼,所有開發都依賴 develop 分支進行。
    • develop 分支作為開發的主分支,也不允許直接提交程式碼。新改動需要切出新的 feature 分支進行,開發完畢後以此分支提 merge request 合併至 develop 分支,目的是保證每個改動都經過了強制程式碼 review,降低程式碼風險。
  • $sub-feature 分支
    • 功能分支,開發新功能的分支。
    • 開發新的功能或者改動較大的調整,從 develop 分支切換出 feature 分支,分支名稱為 feature/xxx
    • 開發完成後合併回 develop 分支並刪除該 feature/xxx 分支。
  • $sub-release 分支
    • 釋出分支,新功能合併到 develop 分支,準備釋出新版本時使用的分支。
    • 當 develop 分支完成功能合併和部分 bug fix,準備釋出新版本時,切出一個 release 分支,來做釋出前的準備,分支名約定為 release/xxx
    • 釋出之前發現的 bug 就直接在這個分支上修復,確定準備發版本就合併到 master 分支,完成釋出,同時合併到 develop 分支。
  • $sub-hotfix 分支
    • 緊急修復線上的 bug 分支。
    • 當線上版本出現 bug 時,從 mater 分支切出一個 hotfix/xxx 分支,完成 bug 修復,然後將 hotfix/xxx 合併到 master 和 develop 分支(如果此時存在 release 分支,則應該合併到 release 分支),合併完成後刪除該 hotfix/xxx 分支。

以上就是在專案中應該出現的分支以及每個分支功能的說明。其中穩定長期存在的分支只有 master 和 develop 分支,別的分支在完成對應的使命之後都會合併到這兩個分支然後被刪除。簡單總結如下:
- $sub-master 分支:線上穩定版本分支。
- $sub-develop 分支:開發分支,衍生出 feature 分支和 release 分支。
- $sub-release 分支:釋出分支,準備待發布版本的分支,存在多個,版本釋出之後刪除。
- $sub-feature 分支:功能分支,完成特定功能開發的分支,存在多個,功能合併之後刪除。
- $sub-hotfix 分支:緊急熱修復分支,存在多個,緊急版本釋出之後刪除。

2.2 分支間操作注意事項

在團隊開發過程中,避免不了和其他人一起協作,同時也會遇到合併分支等一些操作,這裡提供兩個分支操作規範。

  • 同一個分支 git pull 使用 rebase
    首先看一張圖:
    [image:93A9B7AF-ABD7-4F3F-BEDF-6856CC1104E9-2579-000022D825D6BBB2/git_pull_no_rebase.jpg]
    看到這樣的 提交線圖,想從中看出一條清晰的提交線幾乎是不可能的,充滿了 Merge remote-tracking branch ‘origin/xxx’ into xxx 這樣的提交記錄,同時也將提交線弄成了交錯縱橫的圖,沒有了可讀性。
    這裡最大的原因就是因為預設的 git pull 使用的是 merge 行為,當你更新程式碼時,如果本地存在未推送到遠端的提交,就會產生一個這樣的 merge 提交記錄。因此在同一個分支上更新程式碼時推薦使用 git pull --rebase
    下面這張圖展示了預設的 git pullgit pull --rebase 的結果差異,使用 git pull --rebase 目的是修整提交線圖,使其形成一條直線。
    [image:8F9EFF1F-3DA4-4ABD-A213-9474A7144401-2579-000022F9513619EE/git_pull_rebase_diff.jpg]
  • 分支合併使用 --no-ff
    # 例如當前在 develop 分支,需要合併 feature/xxx 分支
    git merge --no-ff feature/xxx
    在解釋這個命令之前,先解釋下 Git 中的 fast-forward: 舉例來說,開發一直在 develop 分支進行,此時有個新功能需要開發,新建一個 feature/a 分支,並在其上進行一系列開發和提交。當完成功能開發時,此時回到 develop 分支,此時 develop 分支在建立 feature/a 分支之後沒有產生任何的 commit,那麼此時的合併就叫做 fast-forward。
    fast-forward 合併的結果如下圖所示,這種 merge 的結果就是一條直線了,無法明確看到切出一個新的 feature 分支,並完成了一個新的功能開發,因此此時比較推薦使用 git merge --no-ff,得到的結果就很明確知道,新的一系列提交是完成了一個新的功能,如果需要對這個功能進行 code review,那麼只需要檢視叉的那條線上的提交即可。
    [image:BC2643E0-6E4A-4828-8117-CEFF6DFE61CB-2579-0000246FC3384240/A974422D-7006-4726-9849-D226EF5F7AC5.png]

2.3 專案分支操作流程示例

這部分內容結合日常專案的開發流程,涉及到開發新功能、分支合併、釋出新版本以及釋出緊急修復版本等操作,展示常用的命令和操作。

  1. 切到 develop 分支,更新 develop 最新程式碼
    git checkout develop
    git pull --rebase
  2. 新建 feature 分支,開發新功能
    git checkout -b feature/xxx
    ...
    git add <files>
    git commit -m “feat(xxx): commit a”
    git commit -m “feat(xxx): commit b”
    # 其他提交
    ...
    如果此時 develop 分支有一筆提交,影響到你的 feature 開發,可以 rebase develop 分支,前提是 該 feature 分支只有你自己一個在開發,如果多人都在該分支,需要進行協調:
    # 切換到 develop 分支並更新 develop 分支程式碼
    git checkout develop
    git pull --rebase
    

git checkout feature/xxx
git rebase develop

git push –force

3. 完成 feature 分支,合併到 develop 分支
```shell
# 切到 develop 分支,更新下程式碼
git checkout develop
git pull --rebase

# 合併 feature 分支
git merge --no-ff feature/xxx

# 刪除 feature 分支
git branch -d feature/xxx

# 推到遠端
git push origin develop
  1. 當某個版本所有的 feature 分支均合併到 develop 分支,就可以切出 release 分支,準備釋出新版本,提交測試並進行 bug fix
    # 當前在 develop 分支
    git checkout -b release/xxx
    

git commit -m “fix(xxx): xxxxx”

5. 所有 bug 修復完成,準備釋出新版本
```shell
# master 分支合併 release 分支並新增 tag
git checkout master
git merge --no-ff release/xxx

# 新增版本標記,這裡可以使用版本釋出日期或者具體的版本號
git tag 1.0.0

# develop 分支合併 release 分支
git checkout develop
git merge --no-ff release/xxx

# 刪除 release 分支
git branch -d release/xxx

至此,一個新版本釋出完成。

  1. 線上出現 bug,需要緊急釋出修復版本
    # 當前在 master 分支
    git checkout master
    

git checkout -b hotfix/xxx

… 進行 bug fix 提交

git checkout master
git merge –no-ff hotfix/xxx

git tag 1.0.1

git checkout develop
git merge –no-ff hotfix/xxx

git branch -d hotfix/xxx

至此,緊急版本釋出完成。

## 3. 提交資訊規範
---
提交資訊規範部分參考  [Angular.js commit messgae](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits) 。
git commit 格式 如下:
`<type>(<scope>): <subject>`
各個部分的說明如下:
- **type 型別,提交的類別**
    - feat: 新功能
    - fix: 修復 bug
    - docs: 文件變動
    - style: 格式調整,對程式碼實際執行沒有改動,例如新增空行、格式化等
    - refactor: bug 修復和新增新功能之外的程式碼改動
    - perf: 提升效能的改動
    - test: 新增或修正測試程式碼
    - chore: 構建過程或輔助工具和庫(如文件生成)的更改
- **scope 修改範圍**
主要是這次修改涉及到的部分,簡單概括,例如 login、train-order
- **subject 修改的描述**
具體的修改描述資訊
- 範例

feat(detail): 詳情頁修改樣式
fix(login): 登入頁面錯誤處理
test(list): 列表頁新增測試程式碼
```
這裡對提交規範加幾點說明:

  1. type + scope 能夠控制每筆提交改動的檔案儘可能少且集中,避免一次很多檔案改動或者多個改動合成一筆。
  2. subject 對於大部分國內專案而已,如果團隊整體英文不是較高水平,比較推薦使用中文,方便閱讀和檢索。
  3. 避免重複的提交資訊,如果發現上一筆提交沒改完整,可以使用 git commit --amend 指令追加改動,儘量避免重複的提交資訊。

參考資料


本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章