为什么 Git 提交信息很重要
提交信息会向后来阅读代码的任何人(包括未来的您)解释这些更改。
三个月后,您不会记得为什么重构了那个数据管道,或为何在某个操作上从 pandas 改用了 polars。提交信息往往是您思考过程的唯一记录。没有它,您只能凭猜或在 Slack 线程和 JIRA 工单里翻找。
下面是提交信息之所以重要的几个更具体的理由。
清晰的提交信息能让代码评审更高效。 评审者可以先扫一眼信息,理解意图,再聚焦于实现是否匹配。含糊的信息会迫使评审者仅凭 diff 来“逆向还原”您的思路。
调试也会更容易。当出现 bug 时,您会用 git log 或 git blame 追溯问题代码是何时引入的。一条像 "fix authentication bug" 的信息毫无帮助;而 "fix token expiration check in auth middleware" 则能把您直接指向问题所在。
团队协作依赖可读的历史记录。 当新人加入项目或有人接手您的工作时,他们会通过阅读提交来理解代码库如何演进。清晰的信息能把 Git 历史转化为真正有用的文档。
归根结底,写一条有描述性的提交信息只需 15–30 秒,却能在未来省下数小时的困惑。
优质 Git 提交信息的核心原则
好消息并不复杂——遵循几条简单原则即可。
为未来的读者而写
提交信息不是写给此刻的您——而是写给六个月后的读者。
那位读者可能是刚入组的同事,想弄清代码库为何如此设计;也可能是您自己,想回忆当时为何做了某个决定。无论是谁,他们都不会拥有您今天的上下文。
聚焦于意图与原因,而不仅是改了什么。diff 会展示“改了什么”,您的信息应解释“为何更改”以及“解决了什么问题”。
清晰且简洁
当您需要在几十条提交中查找时,短小而具描述性的消息更易浏览。
像 "add caching" 这样的信息很模糊;"add Redis caching for API responses" 则一目了然。您在 git log --oneline 中读到它,就能立刻知道该提交做了什么。
主题行应回答:这个提交做了什么? 如果需要超过 50–60 个字符才能说明白,您很可能一次提交了太多更改。
保持一致
仓库内的统一性会让历史更可预期、更易解析。
当每条提交都遵循相同格式,您就能快速浏览历史。您知道去哪里看变更类型、影响范围和描述。坚持统一格式的团队还能自动化生成变更日志,或按类型筛选提交等任务。
选一种风格并坚持下去。如果团队使用祈使语态的现在时,就不要随意切换到过去时。
解释“做了什么和为什么”(而非“如何做”)
代码会展示您如何解决问题。提交信息应解释问题是什么、为何选择这种方案。
不要写“把 load_data() 从 for 循环改成了列表推导式”。要写“让大型 CSV 文件的数据加载提速 40%”。前者描述了代码改动,后者说明了影响。
在有助于未来读者理解决策时补充上下文。如果您在定下方案前尝试了三种做法,可以提一下;如果有关联的缺陷报告或设计决策,也请引用。
Git 提交信息的结构
大多数 Git 提交信息遵循标准的三段式结构:主题行、正文和页脚。
主题行
主题行是一行摘要,会出现在 git log --oneline 和拉取请求列表中。
尽量控制在 50 个字符以内,最多不超过 72。这样可以确保在终端输出和 GitHub 界面中正确显示而不会被截断。如果 50 个字符装不下您的摘要,您很可能试图在一次提交中描述太多更改。
使用祈使语态——写 "add feature",而不是 "added feature" 或 "adds feature"。可以把它理解为补全句子“If applied, this commit will...”。因此 “If applied, this commit will add Redis caching” 读起来自然,而 “If applied, this commit will adds Redis caching” 则不通顺。
示例:
-
fix null pointer exception in data loader -
add caching layer for API responses -
remove deprecated pandas functions
正文(按需撰写)
对于简单更改可省略正文。如果主题行已经完整说明了提交内容,就到此为止。
当需要解释为何更改或提供有助于未来读者理解的上下文时,请添加正文。主题与正文之间留一行空行——Git 依此分隔两部分。
正文应回答:这个更改解决了什么问题?为什么选择这种做法?有无副作用或局限?是否考虑过其他方案?
将正文按 72 个字符换行,以便在终端输出中保持可读性。大多数编辑器都能自动处理。
示例:
add Redis caching for API responses
API response times were hitting 2-3 seconds for repeated queries.
Added Redis with 5-minute TTL to cache query results. This drops
response time to ~50ms for cached queries.
Considered using in-memory cache but Redis lets us scale horizontally
if needed.
页脚(可选)
使用页脚引用相关 issue、拉取请求或不兼容变更。
如果提交修复了某个 GitHub issue,请在页脚添加 Fixes #123 或 Closes #456。合并后 GitHub 会自动关闭该 issue。对于不兼容变更,添加 BREAKING CHANGE:,并描述破坏点与迁移方法。
示例:
remove support for Python 3.7
Python 3.7 reached end-of-life in June 2023. This commit drops
support and updates minimum version to Python 3.8.
BREAKING CHANGE: Python 3.7 users must upgrade to 3.8 or later.
Closes #789
大多数提交不需要页脚——只有在需要链接外部参考或标注不兼容变更时使用。
常见的 Git 提交信息类型及适用场景
许多项目会用提交类型前缀来让人一眼分辨变更类别。
您不必死记硬背一长串标签。目标是让读者无需阅读完整 diff 就能快速识别变更类型。
以下四类值得关注:
-
功能类变更会引入新功能。构建新内容(新的 API 端点、数据处理函数或面向用户的功能)时,可用
feat:或add:。示例:feat: add CSV export for analysis results。 -
缺陷修复用于解决现有问题。纠正不符合预期的行为时,用
fix:。范围从空指针异常到模型中的错误计算皆可。示例:fix: handle missing values in preprocessing pipeline。 -
文档更新改进代码注释、README 或内联文档。不改变代码行为,只是解释得更好时,用
docs:。示例:docs: add usage examples for data loader class。 -
重构与日常维护在不改变行为的前提下改进代码结构。整理代码以更整洁、更易维护时,用
refactor:。更新依赖或调整构建配置等日常任务,用chore:。示例:refactor: extract validation logic into separate module或chore: update pandas to 3.0.0。
选一个最贴切的类型即可,别过度追求“完美”标签——一致性更重要。
撰写更佳 Git 提交信息的规则
以下清单能让您的提交信息更有用。
-
将主题行控制在 50 个字符以内。 这样可以确保在
git log --oneline、GitHub 提交列表和终端输出中完整显示而不被截断。如果实在放不下,最多别超过 72 个字符。 -
使用祈使语态。 写 "add feature",而不是 "added feature" 或 "adds feature"。主题行应能补全句式“If applied, this commit will...”。例如 “If applied, this commit will add caching” 是正确的。
-
用空行分隔主题与正文。 Git 通过这行空白来区分摘要与详细说明。没有它,Git 工具可能错误显示您的信息。
-
主题行末尾不加句号。 既能省字符,且主题行本就不是完整句子。写
fix null pointer in loader即可。 -
将主题行首词大写。写
Add caching for API calls,而不是add caching for API calls。这能让历史记录更统一、更专业。 -
正文解释“为什么”,而非“做了什么”。 diff 已经展示“做了什么”。正文应解释更改背后的原因、您考虑过的替代方案以及权衡。
-
正文按 72 列换行。 这样可避免终端中的自动换行问题,并在不同工具中保持可读性。
-
让每次提交都是“原子”的。 每次提交只包含一个逻辑变更。如果您既修了 bug 又做了重构,请拆成两次提交并分别说明。
优质 Git 提交信息示例
以下是不同场景下的真实示例,展示好提交信息应有的样子。
简单修复
fix: handle NaN values in feature engineering
The preprocessing pipeline crashed when encountering NaN values
in the 'age' column. Added fillna() with median imputation before
scaling features.
之所以有效,是因为它明确了问题(NaN 导致崩溃)、发生位置(预处理流水线,age 列)以及解决方案(使用中位数填充)。
新增功能
feat: add model performance tracking to MLflow
Added automatic logging of model metrics, parameters, and artifacts
to MLflow after each training run. This replaces our manual CSV
logging and makes experiment comparison much easier.
Metrics tracked: accuracy, precision, recall, F1 score
Training time also logged for performance monitoring.
优秀的功能类提交会解释您构建了什么、为何有用,以及有助于读者理解范围的细节。
重构
refactor: split data_loader.py into separate modules
Moved dataset classes to datasets.py, transformation logic to
transforms.py, and utility functions to utils.py. The original
file was 800+ lines and hard to navigate.
No behavior changes - all tests still pass.
重构信息应明确表示并未改变功能,只是结构调整。“所有测试仍然通过”一句能让评审者更安心。
文档更新
docs: add examples for custom loss functions
Previous documentation showed only built-in loss functions.
Added three examples: weighted cross-entropy, focal loss, and
custom regression loss with L1 regularization.
Each example includes code and explanation of when to use it.
文档类提交应说明新增了哪些内容以及为何需要。
引用 issue 或工单
fix: prevent memory leak in batch processing
Large datasets caused memory usage to grow unbounded during batch
processing. The issue was holding references to processed batches
in the results list.
Changed to yield results instead of accumulating them in memory.
Memory usage now stays constant regardless of dataset size.
Fixes #247
在引用 issue 时,要包含足够的上下文,让人不用点进工单也能理解修复内容。底部的 Fixes #247 会在提交合并后让 GitHub 自动关闭该 issue。
所有示例都遵循相同模式:从“做了什么”开始,解释“为什么”,补充对未来读者有帮助的上下文,并在相关时引用关联问题。
将 Conventional Commits 作为提交信息标准
Conventional Commits 是一种流行格式,通过简单的前缀模式为提交信息增加结构。
基本格式
格式如下:type(scope): description。
type 描述变更类型——feat 表示新功能,fix 表示缺陷修复,docs 表示文档,refactor 表示代码重构,等等。可选的scope 指定受影响的代码库部分——如 (auth) 或 (api)。最后的description 解释您做了什么。
示例:
feat(api): add endpoint for batch predictions
fix(auth): prevent token expiration edge case
docs(readme): add installation instructions for Windows
refactor(data): extract validation logic to separate module
请记住这只是一种约定,而非强制。Git 并不在意您是否使用该格式。这主要取决于团队是否决定为了一致性与工具配合而采用这种结构化写法。
何时适合使用 Conventional Commits
自动化发布流程的团队能从中获益最多。
工具可以解析提交历史并自动生成变更日志。当您打标签发布时,工具会扫描自上次发布以来的提交,按类型(feat、fix、docs)分组,并生成格式化的变更日志。这样就免去了人工梳理版本间变更的工作。
Conventional Commits 也支持语义化版本自动化。如果自上次发布以来全是修复,工具会将修订号递增(1.2.3 → 1.2.4);如果新增了功能,则递增次版本号(1.2.3 → 1.3.0);不兼容变更会触发主版本号递增(1.2.3 → 2.0.0)。
但如果团队并未使用自动化发布或变更日志生成,Conventional Commits 可能有些小题大做。它对机器更友好,对人类的帮助相对较少,请酌情考虑。
常见的 Git 提交信息误区
即便是有经验的开发者,写提交信息时也会犯错,这往往源于偷懒,而非不知道怎么写。
以下几个误区请尽量避免。
含糊或泛化的消息
像 "fix bug" 或 "update code" 这样的消息对未来读者毫无帮助。
当您在 git log 中查找某个特定变更时,要浏览几十条提交。写着 “fix bug” 的消息会迫使您点开 diff 阅读代码,才能搞清修了什么;而 “fix null pointer in data preprocessing” 则能让您立刻判断这是否是要找的提交。
泛泛之词浪费大家时间。如果您连自己改了什么都记不清,以至于写不出具体信息,那可能还不该提交。
混合无关更改
一次提交只应包含一个逻辑变更。
当您在一次提交中既修了 bug 又重构了不相关的代码,会让评审更难、git bisect 也失去意义。如果该提交引入了回归,别人不得不理清到底是哪部分改动导致的。如果他们想回滚 仅修复的部分,也做不到——会把重构一并回滚。
请始终把更改拆分为独立提交。一次提交修复 bug,另一次提交重构。每个提交都应能独立回滚而不破坏代码库。
如果您本地已经混在一起了,可用 git add -p 按块暂存文件片段,逻辑分组地提交。
保留“进行中”信息
像 “WIP” 或 “temp fix” 这样的提交在本地可以,但不应进入主分支。
在合并功能分支前,请整理提交历史。将压缩这些 WIP 提交成有意义的提交,并配上合适的信息。把 "asdf"、"trying something" 之类重写为能说明您“实际做了什么”的描述。
使用 git rebase -i 在推送前合并提交、重写信息并重新排序。团队应看到的是干净的历史记录:是什么改变、为什么改变,而不是您的调试过程。
团队使用 Git 提交信息的最佳实践
若想让团队的 Git 历史真正有用,就需要一致性。遵循以下最佳实践。
尽早达成统一风格。 决定是否使用 Conventional Commits、自定义格式,或仅用一套基本规则。选定后全队统一执行。当一半提交写 "feat: add feature",另一半写 "Added new feature",历史就更难浏览,自动化也可能失效。
风格本身不如“人人遵循”重要。有的团队偏好现在时祈使语("add feature"),有的用过去时("added feature")。只要一致,皆可。
把约定文档化,并易于访问。 在仓库中添加 CONTRIBUTING.md,说明提交信息格式并附示例。把它纳入新成员的入职文档。当有人问“这条提交该怎么写?”时,指向文档即可,无需反复解释。
文档应涵盖:采用的基本格式、何时需要正文而非仅主题、如何引用 issue 或工单,以及来自本仓库的几个真实示例。
在代码评审中使用提交信息。 优秀的提交信息能让拉取请求评审更快、更聚焦。评审者可先通过提交信息了解变更脉络,再进入代码细看。
评审时,把提交信息也当作代码来查验。如果信息含糊或易误导,请求在合并前重写。提交清晰的 PR 更易评审、必要时更易回滚、日后也更易理解。
结语
写一条清晰的提交信息只需 30 秒,却能在未来省下数小时的困惑。
把提交历史当作与代码同在的文档。当您写下 "fix bug" 而不是 "fix null pointer in data preprocessing",其实是在给后来阅读这条提交的人——包括您自己——添麻烦。
像对待代码一样对待提交信息。如果您不会把潦草、无注释的代码推向生产环境,也别推送潦草的提交信息。使用祈使语态,主题行控制在 50 字符内,必要时在正文解释“为什么”,并让每次提交保持原子性。
现在您已经知道如何写出有意义的提交信息。想更进一步,请报名我们的 Intermediate Git 课程。

FAQs
什么是好的 Git 提交信息?
优质的 Git 提交信息应有清晰、具描述性的主题行(不超过 50 个字符),能说明更改了什么。主题使用祈使语态(如 “add feature”,而非 “added feature”),当需要解释更改原因时再补充正文。信息应让未来的读者无需深入代码就能理解您的意图。
我该如何组织 Git 提交信息结构?
Git 提交信息由三部分组成:主题行、正文和页脚。主题行是一行摘要,会出现在日志中。然后留一行空行,必要时用正文解释上下文与原因。页脚是可选的,用于引用 issue 或标注不兼容变更。
Git 提交信息常见错误有哪些?
最常见的错误包括:像 “fix bug” 这样含糊其辞的消息、在一次提交中混合无关更改,以及把 “WIP” 或 “temp fix” 等进行中信息留在最终历史中。这些都会让 Git 历史更难搜索与理解。每条提交都应包含一个逻辑变更,并配上清晰、具体的消息。
什么是 Conventional Commits,何时应使用?
Conventional Commits 是一种通过诸如 feat:、fix:、docs: 等前缀加描述来增加结构化的格式。对于使用自动生成变更日志或语义化版本管理的团队很有用,因为工具可以解析提交类型并自动创建发布。如果团队不使用这些自动化,额外的结构可能会带来不必要的负担。
团队如何保持提交信息的一致质量?
团队应尽早达成共识并将其写入 CONTRIBUTING.md,附示例。在代码评审中,像审代码一样审提交信息——若信息含糊或误导,应在合并前要求重写。与采用哪种具体格式相比,一致性更重要。
您是否曾尝试调试半年前写的功能,却只看到诸如 "fix stuff" 或 "updates" 之类的提交信息?
接下来往往就是花 20–30 分钟逐个点开 diff,努力弄清楚改了什么、为什么改。之所以如此,是因为大多数开发者把提交信息当成事后才想起的事情——只是为了尽快推送代码。但提交信息某种程度上就是文档。它与代码同在,所以值得多敲几下键盘把它写清楚。
一条好的 Git 提交信息会解释改了什么以及为何更改。它能帮助团队更快地评审代码、让调试更轻松,并把您的 Git 历史变成某种“进度条”。
本文将介绍您需要的约定、结构和示例,帮助您写出有用的 git 提交信息。
如果您是 Git 新手,这里并不是最佳的起点。建议先学习我们的 Introduction to Git 课程。您可以在一个下午打好基础。