前言
在軟體開發過程中,我們透過 Git 來追蹤與管理程式碼的變更。每次提交(commit)都記錄了程式碼的修改差異、提交描述以及內文。清晰且具體的提交訊息能夠幫助團隊成員快速理解變更原因和具體的修改,這對於確保程式碼管理的效率和團隊合作的順暢至關重要。
在實際開發中,針對一個小功能進行開發時,常常會在尚未正式釋出到主要分支前進行多次微調。由於變更可能非常細微,因此會忽略撰寫清晰的提交訊息,或者提交的標題過於簡略,甚至不寫。隨著提交數量的增加,追蹤每次修改的具體內容變得越來越困難,這也會影響後續的維護和除錯工作。
因此,建議在修改多個檔案時,應將變更內容進行更細緻的拆解,並即時、且確保每次提交都反映具體的變更。此時,使用 GPT 等語言工具可以快速分析變更內容,並根據需求生成一致且詳細的提交訊息,從而確保每次提交都有清晰的記錄。
撰寫提交訊息並沒有一個唯一正確的方式。不同的公司可能有不同的偏好和標準,再加上開發者本身也可能有自己的習慣。也因此,撰寫規範化的提交訊息可以確保不同開發者在溝通時,能夠有更多的一致性與可讀性。
規範化提交內容
規範化提交內容能夠盡可能統一大家的格式,提升提交訊息的可讀性和一致性。在不考慮特定公司的規則,業界大多數約定成俗的提交訊息格式通常包含以下幾個要點:
1
2
3
4
5
| <類別>[範圍(可選)]: <描述>
[內文(可選)]
[備註(可選)]
|
上述規範並非絕對,但一個好的提交內容其架構至少會包含類別
、描述
以及內文
進行整個提交的描述。
類型(Type)
提交訊息的類型是最重要的部分,用來描述這次提交的變更類型。常見的類型包括:
類型 | 說明 |
---|
feat | 新增功能(feature) |
fix | 修復臭蟲(bug) |
docs | 修改文件(documentation) |
style | 不影響程式碼邏輯的修改(如空白、格式、缺少的分號等) |
refactor | 重構程式碼,既不是新增功能,也不是修復 bug |
test | 新增或修改測試 |
chore | 變更建置程序或輔助工具的內容,不影響程式碼邏輯 |
perf | 提升效能的修改 |
ci | 與持續整合相關的修改 |
build | 影響建置系統或外部依賴的變更 |
當然也不侷限於上述類型,也可以像是棄用(deprecate)、釋出(release)等類型,甚至我自己在管理 Hugo 文章的提交,也創造了 post 類型表示一篇新文章的發布。
範圍(Scope)
類型後可以加上範圍,用來指定變更的範圍或模組。這部分是可選的,用來提供更細緻的變更內容,例如:
feat(ui):新增與 UI 相關的功能
fix(api):修復 API 相關的 bug
描述(Description / Subject)
描述部分緊接在類型和範圍後面,用於簡潔地總結這次提交的具體變更。根據慣例,描述使用祈使句(命令)
並且保持在 50 字以內,說明程式碼更動的簡短摘要。有助於其他開發者快速理解提交的目的與內容。
⚠️ 描述結尾不句號。
範例:
feat(auth):新增 OAuth2 驗證機制
fix(database):修正資料庫連線超時問題
內文(Body)
內文部分需空一行開始撰寫,應以清晰且詳盡的方式解釋此次提交的細節和背景。可以包括:
- 變更的原因
- 解決了什麼問題或增加了什麼功能
- 任何相關的技術細節或考量
- 潛在影響(如與其他模組的相容性)
內文可以使用 Markdown 進行排版,例如條列清單、程式碼片段等,以幫助閱讀。每行文字最好保持在 72 個字元以內,以確保在電子郵件或其他工具中的可讀性。
別人怎麼寫?
說了那麼多,我們直接來看看別人怎麼寫😉。
參考以下的範例中,可以歸納出一些共同的規則:
- 簡明的標題,通常 50 字以內,使用現在式動詞,不用標點。
- 內文根據需要詳細說明改動,引用相關的 issue 編號或審查系統。
- 格式標準化(如某些專案使用類別標籤)。
- 類別標籤的差異性。有像是中括號表示類別、冒號分隔功能模組與描述、斜線分割模組與子系統標識。會依據團隊或個人的使用習慣進行微調。
- 簽名以標示責任人,特別是在開源項目中。
當然,假設你更動並提交很多檔案,只寫一句 fix login.py
,會讓人家非常痛苦且難以追蹤,還是要好好說明原因,這部分就看你想當一個怎麼樣的開發者。
1
2
3
4
5
6
7
8
9
10
11
| sshd-socket-generator: do not parse server match config
In order to parse the match config, a connection test specification
needs to be passed. Right now, if a Match directive is used in the
config, the generator fails because no connection test specification is
provided. However, there is actually no reason to parse the match config
at generator time: the Match config is used to modify certain config
options on a per-connection basis. But, we are only concerned with
listening addresses in the generator. Just drop the offending code.
(LP: #2076023)
|
- apple/ml-stable-diffusion 5d5f15
1
2
3
| Add diffusionkit into setup.py
Adds diffusionkit to package installation dependency to avoid erroring out when converting UNet.
|
- apple/ml-stable-diffusion cf4e1e
1
2
3
| Update README.md
Correct wording.
|
- facebook/facebook-ios-sdk 21b018
1
2
3
4
5
6
7
8
9
10
11
12
| Configure IAP Observation Time From Server
Summary:
The IAP observation time refers to how frequently we check a user's transaction history for new transactions in nanoseconds. The default is 3600000000000 nanoseconds or 1 hour. In D63005744, we updated the app events config API to include the ```ios_iap_observation_time```.
This diff updates the app events configuration on the client-side to read and store this value. We then set the IAP observation time based on the cached app events configuration.
Reviewed By: jjiang10
Differential Revision: D63052228
fbshipit-source-id: 0535f88e148da197cf1178653c19c753d7f20c54
|
1
2
3
4
| [rcr] Remove runtimeModule compiler option (#31145)
Now that the compiler always injects `react-compiler-runtime`, this
option is unnecessary.
|
1
2
3
4
5
6
| chore: update Google DNS list
Add 3 new domains that appear in https://www.google.com/supported_domains but not in this list.
For the technically minded, generate your own list with:
curl -fsSL https://www.google.com/supported_domains | sort | sed -E 's%^(.*)$%|www\1^$dnsrewrite=NOERROR;CNAME;forcesafesearch.google.com%'
:-)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| types/lazy: add DeferredInit type
It is sometimes necessary to defer initialization steps until the first actual usage
or until certain prerequisites have been met. For example, policy setting and
policy source registration should not occur during package initialization.
Instead, they should be deferred until the syspolicy package is actually used.
Additionally, any errors should be properly handled and reported, rather than
causing a panic within the package's init function.
In this PR, we add DeferredInit, to facilitate the registration and invocation
of deferred initialization functions.
Updates #12687
Signed-off-by: Nick Hill <mykola.khyl@gmail.com>
|
⭐ 使用 GPT 快速產生提交內容
當我們熟悉了規範化的提交訊息後,便能將其應用到實際開發中,利用 GPT 自動產生提交訊息。以下將說明如何使用 Git 和 VS Code 自動化這個過程。
首先,在 VS Code 中,我們將檔案進行暫存變更(git add)。
之後,開啟下方終端機,並輸入以下指令來產生暫存檔案的 diff log,將結果透過管道(pipe)直接輸出到 VS Code 編輯器中。
1
| git diff --cached | code -
|
也可以加入一些 prompt,可以更快地複製 prompt + diff,並貼到 GPT 中。
Windows 底下加上 prompt:
1
| cmd /c "chcp 65001 & (echo 參考先前輸出: & git log -n 5 --name-only & echo. & echo 不要撰寫廢話,本次 diff 內容如下,幫我產生出符合 git 規範的提交內容: & git diff --cached) | code -"
|
Linux 底下加上 prompt:
1
2
3
4
5
| # 單純 prompt
{ echo "不要撰寫廢話,本次 diff 內容如下,幫我產生出符合 git 規範的提交內容: "; git diff --cached; } | code -
# 參考先前輸出
{ echo "參考先前輸出:"; git log -n 5 --name-only; echo ""; echo "不要撰寫廢話,本次 diff 內容如下,幫我產生出符合 git 規範的提交內容: "; git diff --cached; } | code -
|
此時,VS Code 中會自動彈出新的視窗,內含 prompt 和暫存區的 diff 內容。我們可以將這些內容複製並貼入 GPT,讓其產生出規範化的提交訊息。
GPT 輸入範例,這邊我撰寫更詳細的 prompt,可以精準產出一致性的結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 請幫我撰寫一個符合以下準則的 Git commit 訊息: 標題應遵循此格式: <type>(<scope>): <subject> type 是提交的類別,從以下選項中選擇:feat, fix, docs, style, refactor, test, chore, ci, build, hotfix, perf。 scope 是影響的範圍,可以是資料庫、控制器層、模板層等。 subject 是此提交的簡短摘要,不超過 50 個字元,首字母大寫且不加句點。 內容部分: 包括變更的詳細說明,主要回答 "為什麼" 以及變更背後的原因,每行不超過 72 個字元。 可以包含變更的動機及與先前行為的比較。 備註部分: 如果是重大變更,請以 "BREAKING CHANGE: <描述>" 開頭,解釋變更的原因並提供遷移說明。 請根據下列變更編寫一個符合上述標準的 Git commit 訊息,並以繁體中文呈現。 請跳過不相關的閒聊,直接進入重點。 請以 markdown 代碼格式輸出。
diff --git a/source/j1939/J1939_lib.c b/source/j1939/J1939_lib.c
index 704c318..463f8c0 100644
--- a/source/j1939/J1939_lib.c
+++ b/source/j1939/J1939_lib.c
@@ -125,7 +125,7 @@ uint32_t J1939_Send_Data(uint8_t priority, uint32_t PGN, uint8_t SA, uint8_t *da
j1939_1.this_ecu_tp_cm.control_byte = CONTROL_BYTE_TP_CM_BAM;
}
// 設置傳輸協議連接管理(TP.CM)
- j1939_1.this_ecu_tp_cm.number_of_packages_beging_transmitted = (data_length + 7) / 8; /* Rounding up */
+ j1939_1.this_ecu_tp_cm.number_of_packages_beging_transmitted = (data_length / 7) + ((data_length % 7) != 0); /* Rounding up */
j1939_1.this_ecu_tp_cm.PGN_of_the_packeted_message = PGN;
// 傳送 TP.CM(優先權固定為 6)
|
GPT 根據上述內容可能會產生如下的提交訊息:
1
2
3
4
| fix(J1939_lib): 修正 TP CM 資料包數量計算
修正 TP CM 資料包數量計算邏輯,改為 (data_length / 7) +
((data_length % 7) != 0) 以確保正確的包數計算。
|
透過這個方法,我們能迅速生成符合規範的提交內容,確保提交的品質。
不要使用 gitmoji
過去我曾經使用 Gitmoji,這些看起來精美的 emoji 的確為乏味的提交訊息增添了一些趣味。
然而,我在將提交轉換為 patch 時,產生 patch 檔案後在進行內部 apply 操作時遇到了錯誤。具體的原因已經不太記得了,但應該是由於提交訊息開頭的符號(例如冒號)導致舊版 Git 在 apply 時失敗。因此,Gitmoji 的使用上存在兼容性問題,不太推薦使用。
此外,Gitmoji 的使用也缺乏一致的規範。你對圖示的理解可能和我不一樣,這就容易引發誤解。例如:
- 🐛 通常用於表示修正錯誤,而 🚑️ 則表示修正緊急錯誤,但它們的界限並不明確。
- 🔥 表示移除程式碼。如果因為 🐛(錯誤)而導致程式碼編譯失敗,並且移除了這段程式碼可以解決問題,此時應該使用 🔥 還是 🐛?
- 🔒️ 表示修正安全性問題。如果這個安全性問題本質上是因為 🐛(錯誤)導致的,我應該選擇哪個?
這些都是使用 Gitmoji 時容易出現的疑慮,還有更多使用上的困惑就不一一列舉了。
可以確定的是,清楚撰寫提交訊息的內文,遠比使用一個可能無法引起共鳴的 emoji 更能傳達訊息的精確性和意圖。
此外,也可以通過規範提交訊息的類別
和範圍
,更清晰地表達此次提交針對的部分和改動的性質。
結論
撰寫規範且清晰的 Git 提交訊息,對程式碼的可追溯性、版本控制和團隊合作至關重要。良好的提交訊息能幫助開發者迅速理解變更內容,減少後續維護的困難。使用像 GPT 這樣的自動化工具,可以快速生成高品質的提交訊息,提升開發效率並保持版本控制的一致性。
本文也舉例了一些公開專案的提交訊息,展示了不同開發者之間的風格差異。但整體的共同規則依然不變:具體的類別、清晰簡明的標題,以及可能附帶的詳細內文,必要時引用相關編號進行快速追蹤。
同時,應避免過度依賴圖示化的提交訊息(如 Gitmoji),以確保提交訊息在不同環境中的相容性與可讀性。遵循良好的提交習慣與規範,可以促進團隊協作,並確保程式碼庫的長期穩定性。
有效運用這些工具和規範,將有助於優化開發流程,確保每次變更都能被正確理解和管理,最終提升整體開發品質。
參考資料
- Git - Contributing to a Project
- Conventional Commits
- Commit Message Guide | Blockly | Google for Developers
- Git Commit Messages: 50/72 Formatting