Per-project git commit templates

Tyler Cipriani

每個專案的 Git Commit 範本

原文由 Tyler Cipriani 發布,訂閱此部落格

「大家應該試著把 kernel 的 git log 品質和其他專案比較一下,然後哭著入睡。」

– Linus Torvalds

我永遠記不住你們專案的 commit 規範。

每個專案堅持的規範都不一樣:

不過,git commit 範本可以幫上忙。Commit 範本為 commit 訊息提供了鷹架,在你最需要文件的地方提供說明:就在你撰寫 commit 訊息的編輯器裡。

什麼是 git commit 範本?

當你輸入 git commit 時,git 會打開你的文字編輯器1。Git 可以用 commit 範本預先填入編輯器——就像一份等你填寫的表單。

建立 commit 範本很簡單。

  • 建立一個純文字檔——我的檔案放在 ~/.config/git/message.txt
  • 告訴 git 使用它:
git config --global \
    commit.template '~/.config/git/message.txt'

我的預設範本囊括了我所知道關於撰寫 commit 的一切。

用 IncludeIf 設定專案專屬範本

commit 範本真正厲害的地方在於,你可以為每個專案使用不同的範本。

透過 git 的 includeIf 設定,不同的專案就能使用不同的範本。2

大型專案,像是 Linux kernelgitMediaWiki,都有各自的 commit 規範。

以 Wikimedia 的工作為例,我把 git 儲存庫放在 ~/Projects/Wikimedia,並在全域 git 設定檔(~/.config/git/config)的最下方加入以下設定:

[includeIf "gitdir:~/Projects/Wikimedia/**"]
    path = ~/.config/git/config.wikimedia

config.wikimedia 中,我指向了專屬於 Wikimedia 的 commit 範本。我也覆寫了其他 git 設定,例如 user.emailcore.hooksPath

範例:我的全域範本

我的預設 commit 範本包含三個部分:

  1. Subject(主旨)—— 50 個字元以內,首字大寫,結尾不加標點。
  2. Body(內文)—— 每行 72 個字元換行,與主旨之間空一行。
  3. Trailers —— 採用標準格式,與內文之間空一行。

在每個部分,我都針對格式3與內容加上了提示。

對於 header,指引很簡潔:

# 50ch. wide ----------------------------- SUBJECT
#                                                |
#     "If applied, this commit will..."          |
#                                                |
#     Change / Add / Fix                         |
#     Remove / Update / Document                 |
#                                                |
# ------- ↓ LEAVE BLANK LINE ↓ ---------- /SUBJECT

對於 body,我提醒自己要回答幾個基本問題:

# 72ch. wide ------------------------------------------------------ BODY
#                                                                      |
#     - Why should this change be made?                                |
#       - What problem are you solving?                                |
#       - Why this solution?                                           |
#     - What's wrong with the current code?                            |
#     - Are there other ways to do it?                                 |
#     - How can the reviewer confirm it works?                         |
#                                                                      |

就這樣,除了 git trailers 之外。

錯綜複雜的 git trailers 迷宮

我的範本中有一個區塊,專門放我參與的專案會用到的 trailers。

#     TRAILERS                                                         |
#     --------                                                         |
#     (optional) Uncomment as needed.                                  |
#     Leave a blank line before the trailers.                          |
#                                                                      |
# Bug: #xxxx
# Acked-by: Example User <[email protected]>
# Cc: Example User <[email protected]>
# Co-Authored-by: Example User <[email protected]>
# Requested-by: Example User <[email protected]>
# Reported-by: Example User <[email protected]>
# Reviewed-by: Example User <[email protected]>
# Suggested-by: Example User <[email protected]>
# Tested-by: Example User <[email protected]>
# Thanks: Example User <[email protected]>

這些 trailers 就像是實用的文件線索。Git 可以透過標準指令來解析它們。

舉例來說,如果我想要一份以 Tab 分隔、列出 commit 及其相關任務的清單,我可以用 git log 找出 Bug trailers:

$ TAB=%x09
$ BUG_TRAILER='%(trailers:key=Bug,valueonly=true,separator=%x2C )'
$ SHORT_HASH=%h
$ SUBJ=%s
$ FORMAT="${SHORT_HASH}${TAB}${BUG_TRAILER}${TAB}${SUBJ}"
$ git log --topo-order --no-merges \
      --format="$FORMAT"
d2b09deb12f     T359762 Rewrite Kurdish (ku) Latin to Arabic converter
28123a6a262     T332865 tests: Remove non-static fallback in HookRunnerTestBase
4e919a307a4     T328919 tests: Remove unused argument from data provider in PageUpdaterTest
bedd0f685f9             objectcache: Improve `RESTBagOStuff::handleError()`
2182a0c4490     T393219 tests: Remove two data provider in RestStructureTest

別再死記 commit 訊息規範了

Git commit 範本讓你的大腦不用再記該寫什麼,讓你能專注在真正要說的故事上。

把腦力留給它真正擅長的事吧。


  1. 依序從 git 設定中的 core.editor、shell 中的 $VISUAL$EDITOR,最後 fallback 到 vi↩︎

  2. 你也可以直接在儲存庫的 .git/config 裡設定,如果你在同一個目錄下有多個採用相同規範的儲存庫,includeIf 就很好用。↩︎

  3. 全部參考自 Tim Pope↩︎

本文章由 muse-spark-1.2-contributor 進行翻譯

留言