# 淺談 Git Commit 規範 [![hackmd-github-sync-badge](https://hackmd.io/DsNF8_GOQWqGekjfMe3Omg/badge)](https://hackmd.io/DsNF8_GOQWqGekjfMe3Omg) 目前網路上的 Git Commit 規範多數來自於 Angular 團隊的格式,隨著時間延伸出許多版本。雖然這些資訊在網上隨處可見,為了防止遺失,我還是決定寫一篇文章紀錄,畢竟我五年前看到的文章現在也找不到了。目前的「[Angular Commit Format]」是這樣的。(https://github.com/angular/angular/blob/main/CONTRIBUTING.md)。 ## Commit Format Angular Commit Format 規範分為 header、body 和 footer 三個部分,各部分用空行隔開。其中 header 是必填的,body 視 header 的 type 而定(若 type 為 docs,則必填),footer 是選填的。 ``` <header> <BLANK LINE> <body> <BLANK LINE> <footer> ``` ### Header Header 格式如下(節錄自 Angular Commit Format 的內容): ``` <type>(<scope>): <short summary> │ │ │ │ │ └─⫸ Summary in present tense. Not capitalized. No period at the end. │ │ │ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core| │ elements|forms|http|language-service|localize|platform-browser| │ platform-browser-dynamic|platform-server|router|service-worker| │ upgrade|zone.js|packaging|changelog|docs-infra|migrations| │ devtools │ └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test ``` #### Type Type 用於給 Commit 分類,不同時期的分類有所不同,目前整理如下表,主要差異在於`style` 和 `chore` 被移除了,而 CI/CD 從 `build` 中獨立出來: | Type | 描述 | 新描述 | | --- | --- | --- | | feat | 新功能 | 新功能 | | fix | bug 修復 | bug 修復 | | docs | 僅限文件更新 | 僅限文件更新 | | style | 不影響程式碼含義的更改 (空白字元, 格式化, 少了分號, 其他) | | | refactor | 既不修復錯誤也不增加功能的程式碼變更 | 既不修復錯誤也不增加功能的程式碼變更 | | test | 補測試或更正現有測試 | 補測試或更正現有測試 | | perf | 提升效能的程式碼變更 | 提升效能的程式碼變更 | | build | 影響打包機制,CI配置或外部依賴關係的更改 (example scopes: gulp, broccoli, npm) | 影響打包機制或外部依賴關係的更改 (example scopes: gulp, broccoli, npm) | | chore | 其他不修改 src 或測試文件的更改 | | | ci | | 變更 CI 配置文件和腳本(example:CircleCI, SauceLabs) | #### Scope Scope 表示受影響的 npm 套件的名稱,這是針對 Angular 定義的,其他程式語言可能不適用。對於我來說,大部分情況下會選擇省略,或標註變更的專案名稱。 #### Short Summary(Subject) Short Summary 是對變更的簡潔描述,Angular 規範如下: * use the imperative, present tense: "change" not "changed" nor "changes" * don't capitalize the first letter * no dot (.) at the end 但是我都用中文,所以就句尾不用句號而已。 ### Body Angular 團隊原文如下: > Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes". > > Explain the motivation for the change in the commit message body. This commit message should explain why you are making the change. You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change. 因為我是用中文寫,所以沒有時態問題。實際上,除非修改內容複雜或需特別描述變更原因,否則我會省略 Body。但最近有朋友提到可以使用 Visual Studio 的 Copilot 來幫忙生成 Commit 訊息(若有訂閱 Copilot),我可能會改用其生成的訊息作為 Body 的基底。 ### Footer Footer 可以包含破壞性變更和棄用信息,也可用於引用 GitHub issue、Jira ticket 和其他 PR。例如: ``` BREAKING CHANGE: <breaking change summary> <BLANK LINE> <breaking change description + migration instructions> <BLANK LINE> <BLANK LINE> Fixes #<issue number> ``` 或著 ``` DEPRECATED: <what is deprecated> <BLANK LINE> <deprecation description + recommended update path> <BLANK LINE> <BLANK LINE> Closes #<pr number> ``` `BREAKING CHANGE` 用於重大不兼容變更,`DEPRECATED` 用於描述棄用內容。 大部分情況下,Footer 僅用於關聯需求單號,具體關聯方式取決於所使用的 Issue Tracker。 舉例來說,在 GitHub 中可以使用以下關鍵字將 PR 關聯並關閉 Issue,詳見 GitHub 文檔「[Linking a pull request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)」。 * close * closes * closed * fix * fixes * fixed * resolve * resolves * resolved 在 GitLab 中,可以用以下方式做連結,其中 `123` 替換成相應 ID: * 關聯 Issue:#123 * 關聯 MR:!123 * 關聯 Snippet:$123 GitLab 同樣可以使用 `Closes #123` 或 `Fixes #123`,在合併所屬分支時,關閉相應的 Issue。詳見 GitLab 文檔 Gitlab 文檔「[Tutorial: It's all connected in GitLab](https://about.gitlab.com/blog/2016/03/08/gitlab-tutorial-its-all-connected/)」。 就我個人在實務上來說,由於 PR 或 MR 可能未與 Issue Tracker 關聯,或著希望手動控制關聯,我會用 `issue` 開頭,讓人從語意上就能了解 `#123` 是與 Issue 關聯。 :::info `close` 等關鍵字是不分大小寫的,文件中的範例是因為它在句首,所以字首大寫,如果仔細看在句中出現的,則是用小寫。 ::: ## Commit Tempate 上面簡單的介紹現今主流的 Commit 規範,但實際操作時,可能會忘記一些不常用內容,像我自己就經常忘記一些不常用的 Type。而Git 支援預設的 Commit Template,可以幫助我們統一 Commit 訊息格式。 ### 設定方法 首先,新增一個檔案「.gitmessage.txt」,檔名不能改,內容如下,可依自身需求調整: ```git <type>(<scope>): <subject> # -- Type -- # 必須是以下之一: # # feat: 新功能 # fix: bug 修復 # docs: 僅限文件更新 # style: 不影響程式碼含義的更改 (空白字元, 格式化, 少了分號, 其他) # refactor: 既不修復錯誤也不增加功能的程式碼變更 # perf: 提升效能的程式碼變更 # test: 補測試或更正現有測試 # build: 影響打包機制或外部依賴關係的更改 (example scopes: gulp, broccoli, npm) # chore: 其他不修改 src 或測試文件的更改 # ci: 變更 CI 配置文件和腳本(example:CircleCI, SauceLabs) # # -- Scope -- # 範圍可以是指定提交更改位置的任何內容 例如 編譯, 元素注入, etc. # # init # runner # watcher # config # web-server # proxy # etc. # -- Subject -- # Subject 包含對變更的簡潔的描述: # 使用必要的現在時態: "change" not "changed" nor "changes" # 不要第一個字大寫 # 不要用句點當結尾 # # -- Body -- # 就像在這個題目一樣,使用必須的現在時態: "change" not "changed" nor "changes". # Body 該包含變化的動機,並與以前的行為進行對比。 # # -- Footer -- # Footer 應該包含 Breaking Changes 的資訊並且也是 Github issue close 的參照 # Breaking Changes 應以 "BREAKING CHANGE" 一詞開頭:帶有空格或兩個換行符。然後使用其餘的提交消息。 # Deprecated 應以 "DEPRECATED"一詞開頭:帶有空格或兩個換行符。然後使用其餘的提交消息。 ``` 接著,開啟 Git Bash,並輸入以下命令(其中`~/` 預設會是 `C:\Users\{Windows 帳號}`,或將 `~/` 替換換成要放置檔案的完整路徑): ```git git config --global commit.template ~/.gitmessage.txt git config --global commit.cleanup strip ``` 說明 * `git config`: 這是 Git 的設定指定,用於查看和設定 Git 的配置選項。 * `--global`: 此註記表示該設定將用於全域範圍,即所有的 Git 儲存庫。如果不使用此註記,設定只會生效於當前的 Git 儲存庫。 * `commit.template`: 用來指定 Commit 訊息的 Template 檔案位置。 * `commit.cleanup`: 用來指定在 Commit 時如何處理 Commit 訊息,預設是 `whitespace` 不忽略註解行。 * `strip`: 這是 `commit.cleanup` 選項的值,表示在 Commit 時,將 Commit 訊息中的註解行和多餘的空行移除。 執行完畢後,會在全域的 .gitconfig 增加以下內容,全域的 .gitconfig 在 Windows 預設存放位置在使用者帳號底下,例如:`C:\Users\{Windows 帳號}`。 ``` [commit] cleanup = strip template = {指定路徑}/.gitmessage.txt ``` 如果輸入指定未包含 `--global`,此內容則會產生在該儲存庫的 「./.git/config」檔案裡。 :::info 如果 `template` 設定為 `./.gitmessage.txt`,Git 會使用儲存庫根目錄下的 `.gitmessage.txt` 檔案作為 Commit Template。 ::: Git 一共有三個 config 設定: * System 設定: * 位置:`C:\Program Files\Git\etc\gitconfig`。 * 優先度最低。此設定影響整個系統中的所有使用者和專案,通常是系統管理員設置的全局配置,適合全系統共用的 Git 行為規範。 * Global 設定 * `C:\Users\{Windows 帳號}\.gitconfig`: * 次高優先度。此設定適用於單一使用者,但會被 Local 設定覆蓋。常用來設定個人使用的 Git 選項,對於所有儲存庫都有影響,除非被 Local 設定所取代。 * Local 設定: * `.git\config` * 優先度最高。此設定僅對當前專案有效,覆蓋 Global 和 System 的設定。由於它的影響範圍僅限特定儲存庫,因此對於需要針對專案做特殊設定的情況特別有用。 :::info 三個檔名都不一樣 XD ::: ### 實際使用 當於 Git Bash 輸入 `git commit` 時,會出現訊息 `hint: Waiting for your editor to close the file...`,並開啟記事本,該記事本會包含「.gitmessage.txt」的內容以及以下資訊: ```git # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch main # Your branch is up to date with 'origin/main'. # # Changes to be committed: # modified: "{異動檔案名稱}" ``` 前段「.gitmessage.txt」尾行增加空行是為了與此段訊息分開,此段內容主要在說明請你輸入 Commit 訊息,以 `#` 開頭的行將會被忽略,以及異動檔案清單。 當異動完檔案,並儲存後,則會將檔案內容作為 Commit 訊息。 如果使用其他 Git 版控軟體,不一定會忽略 `#` 開頭的行,所以需要設定 `commit.cleanup strip` 。 目前我已知有支援 Commit Template 的版控軟體如下: * GitKraken: 在儲存庫頁籤點選 File => Preferences... => Commit,會顯示 Commit Template 設定,如果未設定 `commit.cleanup strip` 記得要勾選「Removes comments from commit messages」來忽略 `#` 開頭的行。 * Tortoisegit: 當 `commit.cleanup` 為 `whitespace`,Commit **不**會忽略 `#` 開頭的行。 * Git Extensions: 當 `commit.cleanup` 為 `whitespace`,Commit **仍**會忽略 `#` 開頭的行(感謝同事友情測試)。 * Sourcetree: * Mac 版的 4.2.8 有支援(感謝同事友情測試);Windows 版的 3.4.20 開始支援。 * 當 `commit.cleanup` 為 `whitespace`,Commit **仍**會忽略 `#` 開頭的行。 :::info Sourcetree 3.4.18 版尚未支援 Git Template,但我看在 2024/6/27,官方在把大家喊好幾年的 Jira 單全關閉了,說在 [Commit template message](https://jira.atlassian.com/browse/SRCTREEWIN-3817) 已解決,所以也許後續某個版本有可能會支援了。 Sourcetree 3.4.20 已新增支援,詳見 [Sourcetree release notes](https://product-downloads.atlassian.com/software/sourcetree/windows/ga/ReleaseNotes_3.4.20.html)。 > SourceTree 3.4.20 [17 September 2024] > * Changes: Supporting git commit template feature > * Changes: Upgrade to Git 2.46.0 and Git LFS to 3.5.1 > * Fixed: 'Push changes immediately' checkbox is disabled in No Staging View > * Fixed: Arbitrary code execution vulnerability > * Fixed: Interactive rebase always aborting when a merge is necessary > * Fixed: Silent crash when creating a hotfix > * Fixed: Sourcetree diff treats large .sql files as binary > * Fixed: Windows Line breaks are replaced with Unix breaks on "Discard Hunk" click ::: ### 還原設定 可以用以下指令移除 Git Template 設定: ```git git config --unset --global commit.template ``` 使用以下指令還原忽略註解行的設定: ```git git config --global commit.cleanup whitespace ``` ## 異動歷程 * 2024-07-23 新增。 * 2024-09-20: * 更新 Windows 版 Sourcetree 3.4.20 支援 Git Commit Template 功能。 * 修正設定檔位置的說明。 ###### tags: `Git`