# 编写良好的 CL 描述

CL 描述是一项公开的记录，其内容包含修改了 **什么** 与 **为什么** 这么修改。 虽然你的 CL 只是在你与审核者之间发生，但它是版本控制历史的一部分，若干年之后，很有可能会有成百上千的人阅读。

以后的开发者可能会根据描述搜到你以前写的 CL 。在没有精确数据的情况下，他可能根据自己的模糊记忆搜索 CL。如果所有的信息都只包含在代码里面，描述中几乎没有相关内容，那么定位到你的 CL 将会花费太多的时间。

## 第一行 <a href="#first-line" id="first-line"></a>

* 简短描述做了什么。
* 完整的句子，祈使句。
* 后面空一行。

CL 描述的 **第一行** 应该是一句简短的描述，用以说明 _CL做了_ **什么** 。在第一行后面留一空行。以后有开发者搜索版本控制历史的代码时，这是他们看到的第一行，所以第一行应该提供足够的信息，他们不必阅读代码，也不必阅读整个描述，只需扫一眼便知道 CL 做什么，或者知道这条 CL 与其他 CL 的区别在哪里。 也就是说，第一行应该是独立的，以便阅读代码的人快速的了解代码的功能或作用。

尽量保证第一行简短、重点突出、切中要害。对读者而言，清晰度和实用性是最重要的。

一般而言，CL 描述的第一行是以命令口吻（祈使句）写的一句话。举例说明，我们应该写“ **删除** FizzBuzz RPC，并用写的系统 **替换** 它。”，而不是写成 “ **删除了** FizzBuzz RPC，并 **已经** 用写的系统 **替换** 它。” 当然，第一行写成祈使句就可以了，其他内容不必如此。 (译者注：原文中的反面例子是现在进行时。但在中文中现在进行时与祈使句基本一致，不好翻译。此处改成了现在完成时。)

## 描述内容要提供充分的信息 <a href="#informative" id="informative"></a>

第一行应该是简短、重点突出的摘要，而描述的其他部分应包含详细信息，包括阅读代码的人全面理解修改内容所需的任何补充信息。它可能包括对正在解决的问题的简要描述，以及为什么这是最好的方法。如果该方法有任何缺点，应该指出来。如果有相关背景信息的，如 bug 编号、基准结果和设计文档的链接。

如果包含的链接是外部资源，请考虑访问限制或保留策略，未来的读者可能看不到这些链接。在描述中尽可能包含足够的上下文，以便审核者和未来的读者理解 CL。

即使是小的 CL，也应该包含这些信息。

## 糟糕的 CL 描述 <a href="#bad" id="bad"></a>

“修复 bug”是一个很不恰当的描述。哪个 bug ？你做了哪些事情来修复它？通通都没有。类似糟糕的描述还包括：

* “修复编译。”
* “增加补丁。”
* “把代码从 A 移到 B。”
* “第一阶段。”
* “增加方便的功能。”
* “清除死链。”

以上这些都是我们在真实案例中见过的 CL 描述。作者可能认为他们提供了足够的信息，其实它们不符合 CL 的目的描述。

## 良好的 CL 描述 <a href="#good" id="good"></a>

这是几个良好描述的样例。

### 功能修改 <a href="#function_change" id="function_change"></a>

> RPC：移除 RPC 服务器的消息空闲列表的大小限制。
>
> 服务器（如 FizzBuzz）有大量的消息，可以从重用中受益。使空闲列表更大，并添加一个goroutine，随着时间的推移缓慢释放空闲列表，以便空闲 服务器最终释放所有空闲列表。

前面几句话描述了 CL 做什么的，接下来描述解决了什么问题，为什么这是一个好的解决方案，最后涉及到了一些实现细节。

### 重构 <a href="#refactoring" id="refactoring"></a>

> 构建一个带 TimeKeeper 的 Task，以便使用它的 TimeStr 和 Now 方法。
>
> 在 Task 中增加一个 Now 方法，然后删掉 borglet() 方法（这个方法仅仅被 OOMCandidate 使用，它调用了 borglet 的 Now 方法）。这样就替换掉 Borglet的方法，把它委托给 TimeKeeper。
>
> 让 Tasks 提供 Now 是减少对 Borglet 的依赖所做的一小步。最终，从 Task 上调用 Now 的方式会替代成直接调用 TimeKeeper，我们会逐步实现。
>
> 继续重构 Borglet 层次的长期目标。

第一行描述了 CL 做什么的，以及过去它是怎么改变的。描述的其他部分谈到了具体实现、CL 的上下文，这种方法并不完美，但在朝着完美的方向前进。而且也解释了 _为什么_ 应该这么改。

### 需要一些上下文的小 CL <a href="#small_cl_context" id="small_cl_context"></a>

> 为 status.py 创建一个 Python3 的编译。
>
> 在原始的编译（Python2）旁创建一个 Python3 的编译，让已经使用过 Python3 编译的用户根据某些规则选择 Python3 还是 Python2，而不是依赖于某个路径。 它鼓励新用户尽可能使用 Python3 而不是 Python2，并大大简化了当前正在使用的某些自动编译文件重构工具。

第一句话描述做了什么，其他部分解释 _为什么_ 要这么修改，并向审核者提供了不少额外的上下文信息。

### 使用标签 <a href="#tags" id="tags"></a>

标签是手动输入的，目的是便于对 CL 进行分类。 工具可能支持标签，或者根据团队习惯使用标签。

例如：

* "\[tag]"
* "\[a longer tag]"
* "#tag"
* "tag:"

使用标签是可选的。

当添加标签时，考虑是否要把标签添加到 [CL 描述内容](#informative)中，或[第一行](#first-line)中，以便把它与内容区分开来。

以下是有标签和没有标签的例子：

```{.good}
好的标签样例

// 第一行中的标签保持简短。
[banana] Peel the banana before eating.

// 标签可以内嵌在内容中。
Peel the #banana before eating.

// 标签是可选的。
Peel the banana before eating.

// 如果能保证简短，多个标签也是可接受的。
#banana #apple: Assemble a fruit basket.

// 标签可以放在 CL 描述中的任何位置。
> Assemble a fruit basket.
>
> #banana #apple
```

```{.bad}
不好的标签样例

// 在第一行中包含太多标签（或标签太长）。
//
// 对于这种情况，可以考虑把标签移到描述内容中，或把它修改得更简短。
// 
[banana peeler factory factory][apple picking service] Assemble a fruit basket.
```

### 自动生成的 CL 描述 <a href="#generated_cl_descriptions" id="generated_cl_descriptions"></a>

有些 CL 是有工具自动生成的。如果可能的话，它们的描述也应遵循此处的建议。也就是说，它的第一行应该简短、重点突出、独立的，并且 CL 描述正文应该包含信息丰富的细节，以帮助审核者和未来的代码搜索者了解每个 CL 的功能或作用。

## 提交 CL 之前审核描述 <a href="#review_before_submit" id="review_before_submit"></a>

在审核过程中，CL 可能会发生重大改变（与最初提交审核的 CL 相比）。在提交 CL 之前有必要再审视一遍 CL 描述，确保描述能够正确地反映 CL 做了什么。

下一章: [小 CL](small-cls)
