write-pr-description

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

write-pr-description

编写PR描述

A pull request description has one job: give the reviewer what the diff cannot.
The diff already states what changed. The description states why it changed, what it affects, which decisions were made along the way, and where the author wants attention. Everything below follows from that. When a rule here conflicts with what a specific reviewer needs, serve the reviewer.
create-pr
covers the mechanics of opening the PR. This skill covers what goes in the body.
PR描述的核心作用是:向评审者提供diff无法呈现的信息。
diff已经说明了内容发生了什么变化,而PR描述需要解释变化的原因、影响范围、过程中做出的决策,以及作者希望评审者重点关注的内容。以下所有规则均以此为核心。如果本规则与特定评审者的需求冲突,请优先满足评审者。
create-pr
技能负责处理开启PR的操作流程,本技能则专注于PR正文内容的撰写。

1. Collect the facts before drafting

1. 起草前收集信息

Usually you did the work and already know most of this. When you are describing a branch you did not write, or a PR you have just been handed, start here.
bash
undefined
通常你是代码的编写者,已经了解大部分相关信息。但如果你要描述的是他人编写的分支,或是刚接手的PR,请从以下步骤开始。
bash
undefined

From a checkout of the branch

在分支的本地检出目录中执行

git --no-pager log <base>..HEAD # commit bodies first, they carry the why git --no-pager diff <base>...HEAD --stat
git --no-pager log <base>..HEAD # 先看提交正文,里面包含变化的原因 git --no-pager diff <base>...HEAD --stat

From a PR number, with no local branch

通过PR编号操作,无需本地分支

gh pr view <n> --repo <owner/repo> --json title,commits,files,baseRefName gh pr diff <n> --repo <owner/repo>

Read the commit bodies before the diff. They are usually the richest source of
motivation. Then verify what they claim: a commit message saying "matches the existing
pattern in this file" is an assertion about code, and it is often wrong. Do not forward a
claim you have not checked.

Verify by looking, not by reasoning. The checks worth making are cheap and specific:

- Read what the change deletes. When a change exists to fix something, the defect is
  usually visible in the removed code.
- Ask the system what a thing means, rather than inferring it: `gcloud iam roles
  describe` for a role's permission set, the provider or API schema for a resource's
  fields, the parser for what a marker does.
- Grep a flag across the environment files before claiming it is on or off.
- Open the file a comment or commit message points at, and confirm it says what the
  pointer claims.

One check of this kind usually produces the best sentence in the description.

Gather what the diff cannot tell the reviewer:

- The motivation. What breaks, costs, or stays impossible without this change.
- The linked issue, spec, or design doc, and any spec files committed on the branch.
- Decisions with a real alternative, and why the alternative lost.
- The blast radius: what this can break beyond the files it touches.
- The validation you ran, and what it showed.
- Anything you are unsure of.
gh pr view <n> --repo <owner/repo> --json title,commits,files,baseRefName gh pr diff <n> --repo <owner/repo>

先阅读提交正文再看diff,提交正文通常是最丰富的动机来源。然后验证提交中的表述:比如提交信息说“匹配文件中的现有模式”,这是对代码的断言,但往往不准确。不要转发未经核实的表述。

通过实际查看而非推理来验证。值得做的检查简单且明确:

- 查看被删除的内容。当修改是为了修复问题时,缺陷通常能在被移除的代码中找到。
- 直接查询系统获取信息,而非自行推断:比如用`gcloud iam roles describe`查看角色的权限集,查看提供商或API schema了解资源字段,查看解析器了解标记的作用。
- 在环境文件中全局搜索某个标志,再断言它的开启或关闭状态。
- 打开注释或提交信息指向的文件,确认内容是否与描述一致。

这类检查通常能产出描述中最有价值的句子。

收集diff无法告知评审者的信息:

- 动机:没有本次修改会导致什么问题、额外成本,或是哪些功能无法实现。
- 关联的issue、规格说明或设计文档,以及分支中提交的任何规格文件。
- 存在真实备选方案的决策,以及为何最终选择了当前方案。
- 影响范围:除了修改的文件外,本次变更还可能破坏哪些内容。
- 你执行的验证操作,以及验证结果。
- 任何你不确定的内容。

2. Follow the repository's template

2. 遵循仓库的模板

Check the repository for a PR template. Where there are several, pick the one matching the change. Templates differ per repository, so check every time rather than reusing the shape from your last PR.
The template's own instructions outrank this skill. A template that says "remove this section if it is not relevant" is telling you what this repository's reviewers want. Follow it. The guidance below applies where the template is silent.
  • Keep the headings, their wording, and their order. Reviewers and tooling both scan for them.
  • Answer every section, in your own words, under the heading. Do not reproduce the template's question text, its explanatory links, or its examples. A template with four gate sections can otherwise cost two hundred words to say "no" four times.
  • Where a section does not apply, say so in a clause that shows you considered it ("No new tables"), rather than deleting it or leaving it bare.
  • Tick a box only when its statement is true. Otherwise leave it unticked with a short reason on the same line. Do not delete the box, do not tick it with a caveat attached, and do not restate the box's own text back to the reader.
  • Preserve machine-read content: changelog markers, artifact or media markers, issue linking keys. Check that the marker is live where the template puts it. Some templates show a marker inside an HTML comment that the parser strips, which means a marker left in place is silently ignored. Confirm against the parser or a merged PR.
  • Instructional HTML comments can go once you have answered them.
When no template exists, use this shape, which is the same shape a template would give you:
  1. The opening paragraph from step 3, with no heading above it. It carries both what and why, so there is no separate
    Why
    section.
  2. ## Review guide
    , when step 4 calls for one.
  3. ## What changed
  4. ## Validation
This shape collapses on a small change. A heading over a single line is the same ceremony step 4 warns about, so drop any section that would hold one and let the opening carry it.
检查仓库是否有PR模板。如果有多个模板,选择与本次变更匹配的那个。不同仓库的模板差异很大,因此每次都要检查,不要沿用上次PR的模板结构。
模板自身的优先级高于本技能的指导。如果模板说明“若不相关则移除本节”,这代表该仓库的评审者希望如此,请遵循此要求。以下指导仅适用于模板未明确说明的场景。
  • 保留模板的标题、措辞和顺序。评审者和工具都会依赖这些标题进行扫描。
  • 用自己的话回答每个章节,直接放在标题下方。不要重复模板的问题文本、解释链接或示例。否则,一个包含四个检查项的模板可能需要用200个词来四次回答“否”。
  • 如果某个章节不适用,请用能体现你已考虑过的表述说明(如“无新增表”),不要删除该章节或留空。
  • 只有当复选框的陈述为真时才勾选。否则保持未勾选状态,并在同一行附上简短理由。不要删除复选框,不要勾选后附加说明,也不要重复复选框的文本内容。
  • 保留机器可读的内容:变更日志标记、制品或媒体标记、issue关联关键字。确认标记在模板指定的位置是有效的。有些模板会将标记放在HTML注释中,解析器会忽略这类注释,因此留在其中的标记会被静默忽略。请对照解析器或已合并的PR确认。
  • 回答完模板中的指导性HTML注释后,即可删除这些注释。
如果没有模板,请使用以下结构,这也是模板通常会采用的结构:
  1. 步骤3中的开篇段落,无需上方标题。该段落同时包含变更内容和原因,因此无需单独的“原因”章节。
  2. 当步骤4需要时,添加
    ## 评审指南
    章节。
  3. ## 变更内容
  4. ## 验证情况
对于小型变更,此结构可以简化。如果某个章节只有一行内容,这属于步骤4中提到的冗余形式,因此可以删除该章节,将内容合并到开篇段落中。

3. Write the body

3. 撰写正文

Open with one to three sentences covering what the change does and why. A reviewer who reads only the first paragraph should be able to tell whether they are the right reviewer.
Where the repository has a template, this paragraph goes inside its first content section, whatever that section is called. Do not add a lead above the template's first heading, and do not repeat it once inside.
Then give the substance:
  • Explain the mechanism only where it is not obvious from the code. A new abstraction, a non-local invariant, or an unusual control flow needs a paragraph. A renamed field does not.
  • Name behavior changes explicitly, including ones that are side effects of the main change. These are what break other people. For a permissions change, state the direction: what is now allowed that was not, and what is now refused that was allowed.
  • Record decisions with their rejected alternatives. This is the highest-value content in most descriptions and it cannot be recovered from the diff. Where there was no real alternative, state the decision plainly. Do not manufacture one to fill the slot.
  • Include visual evidence for a user-visible change: a screenshot, or before and after where the change is a modification. Reference only captures that exist.
  • Link the issue, spec, or conversation once. Where there is none, say so only if the repository asks for one, through a template section or a contributing guide. Announcing "no linked issue" in a repository that does not use them is lint compliance rather than information. Never invent a plausible ticket ID to fill the gap; a wrong link costs more than no link.
开篇用1-3句话说明变更内容和原因。仅阅读第一段的评审者应能判断自己是否适合评审此PR。
如果仓库有模板,此段落应放在模板的第一个内容章节中,无论该章节叫什么名称。不要在模板的第一个标题上方添加引言,也不要在章节内重复该内容。
然后撰写核心内容:
  • 仅在代码无法明显体现的情况下解释实现机制。新的抽象、非局部不变量或不寻常的控制流需要用段落说明,而重命名字段则不需要。
  • 明确说明行为变化,包括主变更带来的副作用。这些是影响他人的关键。对于权限变更,要说明方向:哪些操作现在被允许,哪些操作现在被禁止。
  • 记录决策及被否决的备选方案。这是大多数描述中价值最高的内容,且无法从diff中恢复。如果没有真实的备选方案,直接说明决策即可,不要强行编造。
  • 对于用户可见的变更,提供可视化证据:截图,或是变更前后的对比。仅引用已存在的素材。
  • 仅关联一次issue、规格说明或对话。如果没有相关内容,只有当仓库通过模板章节或贡献指南要求时才说明。在不使用issue的仓库中声明“无关联issue”属于合规性表述而非有效信息。切勿编造看似合理的工单ID来填充空白,错误的链接比没有链接更糟糕。

Validation

验证情况

You normally ran the work, so report it: the command and what it showed.
Where you did not, or only partly did, these are the honest shapes. More than one can apply at once: you may have verified a fact yourself and still be waiting on CI for the rest.
  • Nothing ran. State it plainly and name the command the reviewer or CI should run.
  • CI produces the result, because the check needs credentials or an environment you should not use. Name the job, and say what you expect it to show, marked as an expectation rather than an observation. "Expect one destroy and one create, nothing else" gives the reviewer something to check the run against, which is more useful than silence. Phrase it so it cannot be misread as output you saw.
  • The branch adds tests but no run is recorded. Say the tests are added and unrun, so nobody reads the test list as evidence they passed.
  • You could not run it, for want of a device, credentials, or an environment. Say so, and name it as a check you are asking the reviewer to make. This does not cover something you skipped; if you could have run it, run it.
  • Someone else recorded the result, such as a verification noted in an earlier commit. Attribute it or leave it out. Never restate it as your own observation.
Whichever apply, state each once. Repeating "this was not run" in three sections reads as hedging, and buries the one line that says what to run instead.
Never write intent as though it were a result.
通常你已经执行过验证操作,请报告操作命令和结果。
如果你未执行或仅部分执行,请如实说明。以下情况可能同时存在:你可能已自行验证了某些事实,但其余部分仍在等待CI执行。
  • 未执行任何验证:直接说明,并告知评审者或CI应执行的命令。
  • CI将生成结果:因为检查需要你不应使用的凭据或环境。指明作业名称,并说明你预期的结果,注意要标记为预期而非你已看到的输出。例如“预期会销毁一个资源并创建一个资源,无其他操作”,这能让评审者有明确的检查依据,比沉默更有用。表述时要避免被误解为你已看到的输出。
  • 分支新增了测试但未记录执行结果:说明测试已新增但未执行,避免有人将测试列表误认为已通过的证据。
  • 无法执行验证:因为缺少设备、凭据或环境。说明情况,并请求评审者帮忙检查。这不包括你刻意跳过的内容;如果可以执行,务必执行。
  • 他人记录了结果:比如早期提交中提到的验证。可以注明来源或省略,但切勿将其表述为你自己的观察结果。
无论哪种情况,每种情况仅说明一次。在三个章节重复“未执行验证”会显得犹豫不决,且会掩盖说明应执行哪些操作的关键内容。
切勿将意图表述为结果。

Prose

行文风格

Use ASD-STE100 as the baseline: active voice, one topic per sentence, sentences under about 25 words, simple tenses, one term per concept for the whole description. Code identifiers, command lines, and established repository jargon are technical names; leave them alone. See references/plain-language.md for the rules and the exemptions.
以ASD-STE100为基准:使用主动语态,每句一个主题,句子长度控制在约25词以内,使用简单时态,整个描述中同一概念使用同一术语。代码标识符、命令行和已确立的仓库行话属于技术名称,保留原样。请参阅references/plain-language.md了解规则和例外情况。

4. Add reviewer guidance when it is warranted

4. 必要时添加评审指南

Add a review guide when the reading order is not obvious, when you have a specific place you want attention, or when the change can break things well beyond the files it touches. Skip it when a competent reviewer will know where to look without being told.
Put it high, directly after the summary. A reviewer should not have to scroll past compliance checklists to find where to start.
## Review guide
is a reasonable default heading when the template does not supply one.
On a small PR, guidance is a sentence or two, not a section. Fold it into the opening rather than raising a heading over it. A heading on two paragraphs is ceremony, and so is a reading order for six files.
A review guide contains some or all of:
  • A recommended reading order, for PRs large enough that the order matters.
  • Focus areas: what you are unsure of, security-relevant surfaces, decisions with a meaningful alternative, and one-way doors where the ambiguity is genuine.
Write it for a competent engineer. Point at the code and the open question; never explain how to review code. See references/review-guide.md, which opens with a short map of which of its sections you need.
当阅读顺序不明确、你有特定的重点关注区域,或是变更可能影响修改文件以外的大量内容时,添加评审指南。如果资深评审者无需指导就能知道查看位置,则可以跳过。
将评审指南放在靠前的位置,紧跟摘要之后。评审者不应需要滚动过合规清单才能找到开始评审的位置。如果模板未提供标题,
## 评审指南
是合理的默认标题。
对于小型PR,指南只需一两句话,无需单独成节。将其合并到开篇段落中,不要为其添加标题。为两段内容添加标题属于冗余形式,为六个文件指定阅读顺序也是如此。
评审指南可包含以下部分或全部内容:
  • 推荐阅读顺序:适用于规模大到顺序会影响评审的PR。
  • 重点关注领域:你不确定的内容、与安全相关的环节、存在有意义备选方案的决策,以及存在真实歧义的不可逆操作。
为资深工程师撰写指南。指向代码和待解决的问题;切勿解释如何评审代码。请参阅references/review-guide.md,其中开篇简要说明了你需要用到哪些章节。

5. Cut

5. 精简内容

Drafts run long, and the excess is almost never in the thinking. It collects in the parts that feel obligatory: the checklist answers, the inventory of tests, the second statement of something you already said. Those parts are also the easiest to delete, which makes this pass cheap and worth doing every time.
Rough anchors for the whole body, before you start cutting:
  • A test-only, config, or mechanical change with no behavior change: a short paragraph.
  • A small change with a real risk surface: a few hundred words, nearly all of them about the risk rather than the diff.
  • A focused fix or feature: four or five hundred words.
  • A new mechanism with consumers: under a thousand.
  • A very large or foundational change: around a thousand, with most of the extra spent on the reading order and the focus areas.
These are anchors, not limits. Being over one means look harder at the list below; it never means cut a decision.
Then take each paragraph and name the decision it helps the reviewer make. If you cannot name one, delete it. The usual finds:
  • Anything the diff shows at a glance. "The hash-scroll logic was generalized", "the field was renamed", one bullet per changed line, a restatement of the lockfile. The exception is something that looks unintended, such as a name that disagrees with what it binds to. The reviewer can see it but cannot tell it is wrong, so it stays.
  • Paraphrases of comments this diff adds. The reviewer reads them in place, one scroll away.
  • Inventories of the tests you added. Name what is not covered, and roughly how much of the change is tested. A list of test function names reads as padding, especially with no result attached to it.
  • Explanations of how standard tools behave. Terraform replacing a renamed resource, how a test macro polls, when a React effect fires, how a library spawns a child process. Explain this change, not the reviewer's tools.
  • The second statement of a fact. Count them: "no linked issue" and "nothing was run" each belong in exactly one place, and a fact worth stating twice is usually a fact stated badly the first time.
  • Sentences whose only job is to point at another part of the description. Cross references inside one page mean the content is in the wrong place.
  • Sentences about the description itself. "A review guide is included because this change has a wide blast radius." Write the guide; do not justify it.
  • Commit trailers.
    Co-Authored-By
    belongs in the commit, not in the PR body.
Keep, even when cutting hard: the motivation, the behavior changes, the decisions and their rejected alternatives, the open questions, and the blast radius. These are the reason the description exists. When something has to go, cut mechanism before you cut a decision.
草稿通常会过长,冗余内容几乎都不是思考过程的核心,而是集中在看似必须的部分:清单回答、测试清单、重复表述的内容。这些部分也最容易删除,因此每次都值得进行精简。
精简前的正文长度参考:
  • 仅涉及测试、配置或无行为变化的机械性变更:简短段落。
  • 存在真实风险的小型变更:几百词,几乎全部用于说明风险而非diff内容。
  • 针对性修复或功能:四五百词。
  • 带有使用者的新机制:不超过一千词。
  • 非常大或基础性的变更:约一千词,额外内容主要用于说明阅读顺序和重点关注领域。
这些是参考值而非限制。超过参考值意味着需要更仔细地检查以下内容,但绝不意味着要删除决策相关的内容。
然后逐段分析,明确该段落帮助评审者做出什么决策。如果无法明确,删除该段落。常见的冗余内容包括:
  • diff一眼就能看到的内容。比如“哈希滚动逻辑已通用化”“字段已重命名”、每行变更对应一个项目符号、重复lockfile的内容。例外情况是看似无意的变更,比如名称与绑定内容不符。评审者能看到但无法判断是否错误,因此需要保留说明。
  • 本次diff新增注释的转述。评审者只需滚动就能看到注释内容。
  • 新增测试的清单。说明未覆盖的内容,以及变更的测试覆盖率大致情况。测试函数名称列表会显得冗余,尤其是未附带结果时。
  • 标准工具行为的解释。比如Terraform如何替换重命名的资源、测试宏如何轮询、React effect何时触发、库如何生成子进程。请解释本次变更,而非评审者使用的工具。
  • 同一事实的重复表述。统计一下:“无关联issue”和“未执行任何验证”各只需出现一次,值得重复的事实通常是第一次表述不当。
  • 仅用于指向描述其他部分的句子。单页内的交叉引用意味着内容位置不当。
  • 关于描述本身的句子。比如“因本次变更影响范围广,故包含评审指南”。直接撰写指南即可,无需解释理由。
  • 提交尾部信息。
    Co-Authored-By
    属于提交信息,不应放在PR正文中。
即使大幅精简也要保留的内容:动机、行为变化、决策及被否决的备选方案、待解决问题、影响范围。这些是PR描述存在的意义。如果必须删除内容,先删除实现机制相关内容,再考虑删除决策相关内容。

6. Self-check

6. 自我检查

  • Does the first paragraph let a reviewer decide whether the PR is theirs?
  • Does every claim about testing describe something that ran, or say plainly that it did not?
  • Have you verified every factual claim carried over from a commit message?
  • Did the cut take a decision, a rejected alternative, or an open question with it? Those are the first things to go when you compress, and the last things you should lose. Put them back.
  • Does the description match the branch as it stands now, rather than the path you took to get there?
  • If there is reviewer guidance, is it near the top?
  • 第一段是否能让评审者判断自己是否适合评审此PR?
  • 所有关于测试的表述是否都说明了已执行的操作,或是明确说明未执行?
  • 你是否验证了从提交信息中沿用的所有事实断言?
  • 精简过程中是否删除了决策、被否决的备选方案或待解决问题?这些内容在压缩时最容易被删除,但也是最不应丢失的。请将它们恢复。
  • 描述是否与当前分支的内容一致,而非你开发过程中的某个阶段?
  • 如果有评审指南,是否放在靠前的位置?

Anti-patterns

反模式

Narrating the branch's own history. The most common failure. Sentences like "this PR previously included unit tests, which were removed after review feedback", or "the description above overstated this and has been corrected", describe a transition that does not exist in the diff the reviewer is reading. The reviewer sees one state against the base. Describe that state.
Note what survives the rule: the reasoning usually still matters, only the transition goes. "The tests were removed because they only reasserted the match arms" becomes "there are no unit tests here, because a test at this layer would only reassert the match arms".
This holds however long the branch is. A branch with thirty commits still reaches the reviewer as one state against the base.
Restating the diff. A file-by-file inventory is the standard way to write something long that carries no information.
Unverified claims, about anything. Inflated test claims are the familiar case ("fully tested", "no regressions"), but a confident wrong claim about mechanism is more dangerous, because a reviewer is less likely to check it. Before asserting what a role permits, what a flag gates, or what a function guarantees, verify it.
Grading your own work. "Comprehensive", "robust", "clean", "properly". Padding that costs credibility.
Lecturing the reviewer. "Please check for edge cases and make sure the error handling is correct." A competent reviewer already does this, and it displaces the specific pointers only you can give.
Leaving a stale description. After a rework or a force-push, rewrite the body to describe the current branch. Do not append a revision log to the bottom.
叙述分支的历史过程:最常见的错误。比如“此PR之前包含单元测试,在评审反馈后已移除”或“上述描述存在夸大,已修正”,这类句子描述的是评审者看到的diff中不存在的过渡过程。评审者看到的是相对于基准分支的当前状态,请描述该状态。
注意规则的例外:推理过程通常仍然重要,只需删除过渡描述。比如“测试已移除,因为它们仅重复断言匹配分支”可改为“此处无单元测试,因为该层级的测试只会重复断言匹配分支”。
无论分支存在多久,此规则均适用。即使分支有30个提交,评审者看到的仍然是相对于基准分支的当前状态。
重复diff内容:按文件逐一罗列是撰写冗长且无信息内容的标准方式。
未经核实的断言:夸大的测试断言是常见情况(如“完全测试”“无回归”),但关于实现机制的错误断言更危险,因为评审者更可能不会检查。在断言角色权限、标志作用或函数保证之前,请务必验证。
自我评判工作:比如“全面”“健壮”“简洁”“恰当”。这类表述会降低可信度。
说教评审者:比如“请检查边缘情况,确保错误处理正确”。资深评审者自然会这么做,这类表述会挤占只有你能提供的具体指引的空间。
保留过时的描述:在重写或强制推送后,请重写正文以描述当前分支。不要在底部追加修订日志。