# 撰写良好的提交消息

* 原文链接：[Writing Good Commit Messages](https://freebsdfoundation.org/wp-content/uploads/2020/11/Writing-Commit-Messages.pdf)
* 作者：**ED MASTE**

## 为何提交信息很重要？

当你在 Git、Subversion 或其他版本控制系统（VCS）中提交更改时，你会被要求写一些描述提交的文本——提交信息（Commit Messages）。那么，提交信息有多重要呢？你是否应该花费相当多的精力去写它？如果你写的是“修复了一个 bug”，这真的很重要吗？

大多数项目有不止一个开发者，并且持续一段时间。提交信息是与当前和未来的其他开发者沟通的一个非常重要的方法。

FreeBSD 拥有数百名活跃的开发者和数十年的历史，涉及数十万次提交。在这段时间里，开发者社区已经学会了良好的提交信息有多么宝贵；有时这些是通过痛苦的教训学到的。

提交信息至少有三个作用：

* 与其他开发者沟通

FreeBSD 的提交会生成邮件，发送到各种邮件列表。这些邮件包括提交信息以及补丁本身。提交信息还可以通过像 `git log` 这样的命令查看。这些信息旨在让其他开发者了解正在进行的更改；其他开发者可能希望测试这些更改，可能对某个主题感兴趣，想要更详细地审查，或者可能有自己的项目在进行，并且从互动中受益。

* 让更改可发现

在一个有着悠久历史的大型项目中，在调查问题或行为变化时，可能很难找到相关的更改。冗长且详细的提交信息可以方便地进行搜索，找出可能相关的更改。例如，使用 `git log --since 1 year --grep USB timeout`。

* 提供历史文档

提交信息用于为未来的开发者记录更改，可能是在几年或几十年后。这些未来的开发者甚至可能是你，原始作者。今天看起来显而易见的更改，过一段时间后可能就不那么显而易见了。

`git blame` 命令会将每一行源文件标注上进行更改的提交（哈希值和主题行）。

在确立了提交信息的重要性后，以下是一个良好的 FreeBSD 提交信息的元素：

* 以主题行开始

提交信息应以一行简短的主题开始，简要概括更改内容。主题应该能够让读者快速判断该更改是否值得关注。

* 保持主题行简短

主题行应尽可能简短，同时保留所需的信息。这有助于提高浏览 `git log` 的效率，并使 `git log --oneline` 能够在 80 列的行内显示短哈希和主题行。一个好的经验法则是保持在 63 个字符以内，如果可能，目标应是 50 个字符及更少。

* 如果适用，主题行前缀加上组件名

如果更改涉及某个特定组件，主题行可以加上该组件名并以冒号（`:`）结尾。

```sh
✓ foo: Add -k option to keep temporary data
```

在上述建议的 63 个字符限制内包括前缀，以便避免 `git log --oneline` 换行。

* 主题首字母大写

主题本身的首字母要大写。如果有前缀，除非必要（如 `USB:`），否则无需大写。

* 主题行不要以标点符号结尾

不要以句号或其他标点符号结尾。在这方面，主题行就像新闻头条，或电子邮件中的主题标题。

* 用空行分隔主题和正文

用空行分隔主题和正文。

一些微不足道的提交不需要正文，只有主题行。

```sh
✓ ls: Fix typo in usage text
```

* 限制消息为 72 列

`git log` 和 `git format-patch` 会将提交信息缩进四个空格。72 列换行使右边缘有一致的对齐边距。将消息限制在 72 个字符以内还可确保提交信息格式化后的补丁在 RFC 2822 建议的电子邮件行长度限制（78 个字符）以下。这个限制与多种可能渲染提交信息的工具兼容；较长的行可能导致换行不一致。

* 使用现在时、命令语气

这有助于简短的主题行，并提供一致性，包括自动生成的提交信息（例如，`git revert` 生成的提交信息）。当阅读提交主题列表时，这一点很重要。可以将主题视为完成句子“when applied, this change will …”的部分。

```sh
✓ foo: Implement the -k (keep) option
✗ foo: Implemented the -k option
✗ This change implements the -k option in foo
✗ -k option added
```

* 关注“做了什么”和“为什么做”，而非“如何做”

解释更改的目标是什么，为什么要做这个更改，而不是怎么做。

不要假设读者已经了解问题。解释该更改的背景和动机。如果有基准数据，可以包含在内。

如果更改存在限制或不完整的方面，请在提交信息中描述这些内容。

* 考虑是否有部分提交信息应该改为代码注释

有时，在写提交信息时，你可能会写出一两句话，解释更改中一些棘手或令人困惑的部分。这时，可以考虑是否将这些解释作为代码注释放在代码中，这样会更有价值。

* 为未来的自己写提交信息

在写提交信息时，你掌握了所有背景信息——是什么促使了这个更改，考虑并拒绝的替代方案，更改的局限性等等。想象一下，几年后你回顾这个更改时，写出提交信息的方式应该能够提供这些必要的背景。

* 提交信息应该独立存在

你可以包括对邮件列表帖子、基准结果网站或代码审查链接的引用。然而，提交信息应该包含所有相关信息，以防这些引用在未来不再可用。

类似地，提交可能会引用先前的提交，例如修复 bug 或还原提交。在引用的提交（或其他合适的简短引用）中，除了提交标识符（修订号或哈希值）外，还应该包括引用提交的主题行。随着每次版本控制系统的迁移（从 CVS 到 Subversion 再到 Git），以前系统中的修订标识符可能变得难以跟踪。‘

* 在页脚中包含适当的元数据

提交信息的最后一段可能包含一个或多个标准元数据标签。FreeBSD 中使用的标准标签有：

| 标签                    | 描述                               |
| --------------------- | -------------------------------- |
| PR                    | FreeBSD 问题报告（Bugzilla）编号         |
| Submitted by          | 原作者的 ID（如果不是提交者）                 |
| Reported by           | 报告问题的第三方 ID                      |
| Reviewed by           | 审阅者的 ID                          |
| Tested by             | 测试此更改的人员的 ID                     |
| Approved by           | 批准此更改的导师或代码所有者                   |
| Obtained from         | 来自另一个项目的更改源                      |
| MFC after             | 从 Current 合并到 Stable 前的时间周期      |
| MFC with              | 与此更改一同合并的关联提交                    |
| MFH                   | 用于合并请求的 Ports 季度分支               |
| Relnotes              | 是否应包含此更改的发布说明（是/否）               |
| Security              | 与安全问题相关的外部参考，例如 CVE 编号           |
| Sponsored by          | 资助此更改的组织或事件                      |
| Differential Revision | FreeBSD Phabricator 实例中代码审查的完整链接 |

“ID”表示一个 FreeBSD 用户 ID 或一个名字和电子邮件地址。多个 ID 可以作为逗号分隔的列表呈现，或者通过在后续行中重复元数据标签来表示。

***

**ED MASTE** 管理着 FreeBSD 基金会的项目开发工作。他还是选举产生的 FreeBSD 核心团队的成员。除了 FreeBSD，他还为多个其他开源项目做出了贡献，包括 LLVM、ELF 工具链、QEMU 和 Open vSwitch。他与妻子 Anna 以及儿子 Pieter 和 Daniel 一起住在加拿大的基奇纳 - 滑铁卢。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/qi-kan/20200910-gong-xian-yu-ru-men/commit.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
