☰
commit-messages-guide:Git 提交信息编写与提交历史整理的完整实战指南
2026/10/15 16:54:15 网站建设 项目流程
  • 教程
  • 版本控制

【免费下载链接】commit-messages-guide

A guide to understand the importance of commit messages and how to write them well

项目地址:https://gitcode.com/gh_mirrors/co/commit-messages-guide
点击查看免费下载

本指南以开源仓库 commit-messages-guide 的葡萄牙语版官方文档(README_pt-BR.md)为骨架展开,系统讲解 commit 的本质(快照而非差异存储)、提交信息为何重要、十余项被广泛验证的编写最佳实践,以及通过rebase、squash、cherry-pick、交互式暂存等命令规划与重写提交历史的方法。读完本文,你将能够写出结构规范、语义清晰、便于代码审查与回溯的高质量提交信息,同时掌握何时以及如何安全地整理提交历史。

仓库背景:一份多语言维护的提交信息指南

commit-messages-guide 是一个纯文档仓库,不含任何源代码或可执行程序,其内容全部由一组 Markdown 文件构成:英文主文档 README.md、包括葡萄牙语 README_pt-BR.md 在内的 18 种语言版本、贡献规范 CONTRIBUTING.md、代码所有者清单 CODEOWNERS 与 LICENSE。

需要特别说明的一点是:葡萄牙语版本虽然早于英文版编写,但正如文档自身在开篇注释(README_pt-BR.md)中所述,英文版包含一些更详尽的文本与更完善的引用。因此,本文在严格继承葡萄牙语版本完整内容的基础上,会适度引入英文主文档(README.md)中属于同一主题的补充章节(如 PR 消息撰写、提交签名等),以呈现一个信息更完整的知识体系。

什么是 commit?

用最简单的话说,commit 是你本地文件的一份快照(snapshot),被写入本地仓库。这与很多人的直觉相反:Git 存储的并不只是文件之间的差异,而是所有文件的完整版本;只有当某个文件在两个 commit 之间没有发生变化时,Git 才会只存储一个指向上一次快照中相同文件的引用,从而避免重复占用空间。

这个"快照模型"对提交信息的写作有直接启示:既然每个 commit 都是项目在某一时刻的完整记录,那么提交历史就是项目演进过程的唯一可信档案,而每一行提交信息就是这份档案的"标题"与"摘要"。历史能否被后人高效阅读,完全取决于这些标题写得好不好。

为什么提交信息很重要?

README_pt-BR.md 在"Por que as mensagens são importantes?"(为什么提交信息重要?)一节中给出了四条核心理由:

  • 加快并简化代码审查(code review):审查者无需逐行猜测改动意图,读信息即可快速把握变更方向;
  • 帮助理解"发生了什么":一条清晰的提交信息本身就是变更的说明文档;
  • 解释代码无法表达的"隐藏原因":很多决策(权衡、约束、历史包袱)只存在于提交者的脑子里,只能靠文字传达;
  • 方便故障排查与调试:让未来的维护者搞清楚"为什么改"以及"怎么改的",从而更快定位问题。

要最大化这些收益,就需要一套被反复验证的编写规范,这正是本指南的核心价值所在。

编写提交信息的最佳实践

以下实践综合自作者经验、互联网文章与其他指南,逐条展开。

1. 使用祈使句(Imperative)

# Good Use InventoryBackendPool to retrieve inventory backend
# Bad Used InventoryBackendPool to retrieve inventory backend

为什么必须用祈使句?因为提交信息描述的是该变更"将要做什么"(does),而不是"已经做了什么"(was done)。祈使句让信息读起来像一条对仓库下达的指令,与 Git 内部生成的Merge branch ...、Revert ...等自带提交的措辞风格天然一致。

2. 首字母大写

# Good Add `use` method to Credit model
# Bad add `use` method to Credit model

文档特别指出,这是一条颇具争议、且作者本人认为重要性最低的规则——选择大写首字母的唯一理由,只是遵循"句子开头大写"的通用语法习惯。是否大写因人、因团队、因语言而异,真正的关键是:选定一个标准并始终如一地执行。

3. 让信息自解释,无需查看源码

提交信息应当独立传递完整语义,读者不打开 diff 就能明白改动内容:

# Good Add `use` method to Credit model
# Bad Add `use` method
# Good Increase left padding between textbox and layout frame
# Bad Adjust css

在多次提交、多项变更与大规模重构的场景下(例如Add use method这类信息出现在一连串提交中时),清晰的信息能帮助审查者理解提交者当时的思考脉络。

4. 用正文解释"为什么""为了什么""怎么做"及额外细节

信息主题(subject)与正文(body)之间用一个空行分隔;额外的空行会被视为正文的一部分。正文应当聚焦于"为什么"而非"是什么"——如果提交信息只是把 diff 复述一遍,就值得重新思考写法。-、*、反引号等字符是提升正文可读性的常见手段。

三个完整的正面示例:

# Good Fix method name of InventoryBackend child classes Classes derived from InventoryBackend were not respecting the base class interface. It worked because cart was calling the backend implementation incorrectly.
# Good Serialize and deserialize credits to json in Cart Convert the Credit instances to dict for two main reasons: - Pickle relies on file path for classes and we do not want to break up everything if a refactor is needed - Dict and built-in types are picklable by default
# Good Add `use` method to Credit Change from namedtuple to class because we need to setup a new attribute (in_use_amount) with a new value

注意观察这三个例子的共性:主题一句话概括"做了什么";正文紧接着解释"为什么这样做"——要么是修复了某个接口约束被破坏的问题,要么是出于序列化稳定性与重构安全性的权衡,要么是为了新增属性而更换数据结构。这种"主题+理由"的结构正是正文存在的意义。

5. 避免无上下文、过于笼统的信息

以下都是应当避免的反面典型:

# Bad Fix this Fix stuff Agora vai Change stuff Adjust css

这类信息对审查者和未来维护者毫无帮助——它们既没有说明问题,也没有说明方案。

6.(补充)避免 "this PR / this commit / this patch" 之类的自我指涉措辞

英文主文档(README.md)补充了一条重要规则:不需要在信息里指代提交本身——读者当然知道这是一条提交、补丁或 PR。

# Bad This commit does x and y... This PR does x and y... This Patch x and y... # Good X and y are done...

7.(补充)避免个人化语言(如人称代词)

从学术写作中可以借鉴的一条经验是:提交信息应当避免使用个人化语言,保持客观中性:

# Bad I fixed the problem. # Good The problem has been fixed by doing x and y...

8. 控制字符长度

据《Pro Git Book》中的提交规范建议:主题行控制在 50 个字符以内,正文每行约 72 个字符。50/72 这两个数字是为了让信息在git log、git shortlog等终端工具中保持整齐的排版,也强制提交者把信息写得精炼。

9. 保持语言的一致性

语言一致性需要从两个视角分别落实:

  • 项目所有者视角:选定一种语言,用它撰写所有提交信息。理想情况下,该语言应与代码注释、本地化项目的默认翻译语言等保持一致;
  • 贡献者视角:使用与现有提交历史相同的语言来撰写自己的提交信息。
# Good ababab Add `use` method to Credit model efefef Use InventoryBackendPool to retrieve inventory backend bebebe Fix method name of InventoryBackend child classes
# Good(葡萄牙语示例) ababab Adiciona o método `use` ao model Credit efefef Usa o InventoryBackendPool para recuperar o backend de estoque bebebe Corrige nome de método na classe InventoryBackend
# Bad(混用英语与葡萄牙语) ababab Usa o InventoryBackendPool para recuperar o backend de estoque efefef Add `use` method to Credit model cdcdcd Agora vai

10. 使用标准模板

README_pt-BR.md 的"Exemplo de formato"一节给出了一个直接可用的完整模板。该模板最初由 Tim Pope 编写,并收录于《Pro Git Book》:

Summarize changes in around 50 characters or less More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of the commit and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); various tools like `log`, `shortlog` and `rebase` can get confused if you run the two together. Explain the problem that this commit is solving. Focus on why you are making this change as opposed to how (the code explains that). Are there side effects or other unintuitive consequences of this change? Here's the place to explain them. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here If you use an issue tracker, put references to them at the bottom, like this: Resolves: #123 See also: #456, #789

模板的要点可以归纳为四层:第一行主题 ≤50 字符;空行之后是"为什么"的说明(聚焦原因而非手段,并交代副作用);再之后是补充段落与项目符号列表;最后在底部附上问题跟踪器引用(Resolves: #123、See also: #456, #789)。

规划与重写提交历史:Rebase 与 Merge 的选择

编写好单条提交信息之后,下一个层面是规划整段历史。文档这一节是对 Atlassian 的《Merging vs. Rebasing》教程的 TL;DR 浓缩。

Rebase:把分支提交逐个"搬"到目标分支之上

TL;DR:将你分支上的提交,逐个应用到基础分支之上,生成一棵新的树。结果是提交历史呈现一条干净的直线,没有多余的合并节点。

Merge:用合并提交把两棵树缝合

TL;DR:创建一个新的提交(即 merge commit,合并提交),其中包含你所在分支与基础分支之间的差异。合并会保留双方各自的历史脉络,代价是在历史中留下合并节点。

为什么有人偏爱 rebase?

文档作者明确表示个人更倾向于 rebase,理由包括:

  • 历史更"干净":没有散布在历史中、无意义的 merge commit;
  • 所见即所得(WYSIWYG):在 code review 时,你看到的是 master 与分支之间真实的 diff,所有改动都能定位到某个具体且"有名有姓"的提交,而不是被藏在 merge commit 里;
  • 复杂冲突由提交者解决,并归属到一条带正当消息的提交内:没有人会去深挖并审查 merge commit 的内部,这正是 merge commit 的危险所在——避免它们,才能确保每处改动都落在它应有的提交里。

何时该 squash?

Squash 是把一串提交压缩合并成一个提交的过程。在以下几种场景中尤其适用:

  • 历史中存在大量缺乏上下文的补充性提交(拼写修正、格式调整、遗漏的内容);
  • 分散在多个提交中、但合在一起才更有意义的改动;
  • 需要重写的 WIP(work in progress)草稿提交。

何时应避免 rebase 或 squash?

在公共提交、或多人共同工作的共享分支上,应避免 rebase 与 squash。二者的本质都是重写历史、覆盖既有提交。如果对共享分支上的提交(即已推送到远程仓库、或来自其他分支的提交)执行这类操作,会造成分支树分叉与冲突,导致协作者丢失本地或远程的更改,引发混乱。

实用 Git 命令:整理提交历史的工具箱

git rebase -i:交互式变基

用于压缩提交(squash)、编辑消息、重写/删除/重排提交等。文档给出的完整示例非常有趣:其中的每个pick行,正是本仓库自身历史上真实提交信息——它们本身就是"信息自解释"的最佳实例(Improve description and update document title、Add contributing section、Add "Rebase vs Merge" section……):

pick 002a7cc Improve description and update document title pick 897f66d Add contributing section pick e9549cf Add a section of Available languages pick ec003aa Add "What is a commit" section" pick bbe5361 Add source referencing as a point of help wanted pick b71115e Add a section explaining the importance of commit messages pick 669bf2b Add "Good practices" section pick d8340d7 Add capitalization of first letter practice pick 925f42b Add a practice to encourage good descriptions pick be05171 Add a section showing good uses of message body pick d115bb8 Add generic messages and column limit sections pick 1693840 Add a section about language consistency pick 80c5f47 Add commit message template pick 8827962 Fix triple "m" typo pick 9b81c72 Add "Rebase vs Merge" section # Rebase 9e6dc75..9b81c72 onto 9e6dc75 (15 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out

在交互式编辑器中,最常用的几个指令含义如下:

指令缩写作用
pickp保留该提交
rewordr保留提交,但编辑其提交信息
edite保留提交,但停下来允许git commit --amend修改
squashs将该提交并入前一个提交(消息会合并)
fixupf同squash,但丢弃本提交的日志消息
execx用 shell 执行命令行剩余部分
dropd删除该提交

同时要牢记编辑器里的三条警告:行可以重排并按从上到下的顺序执行;删除某一行意味着该提交将永久丢失;如果删光所有行,则整个 rebase 会被中止。

fixup:轻量级清理

fixup的价值在于:可以轻松清理提交,而无需进行一次复杂的 rebase。它的典型用法是配合git commit --fixup=<commit>创建一条"补丁提交",再通过git rebase -i --autosquash自动把补丁并入目标提交并丢弃多余消息——适合处理拼写修正、格式调整这类不值得单独留痕的小改动。

git cherry-pick:把提交搬到正确的分支

当你不小心把提交做到了错误的分支上时,cherry-pick可以把这个提交原样应用到目标分支,无需重新编码:

$ git cherry-pick 790ab21 [master 094d820] Fix English grammar in Contributing Date: Sun Feb 25 23:14:23 2018 -0300 1 file changed, 1 insertion(+), 1 deletion(-)

git add/checkout/reset --patch(-p):按 hunk 精细控制

假设我们手头有一个如下 diff(文档以 README.md 的一次真实修改为例):

diff --git a/README.md b/README.md index 7b45277..6b1993c 100644 --- a/README.md +++ b/README.md @@ -186,10 +186,13 @@ bebebe Corrige nome de método na classe InventoryBackend `` # Bad (mixes English and Portuguese) ababab Usa o InventoryBackendPool para recuperar o backend de estoque -efefef Add `use` method to Credit model cdcdcd Agora vai `` +### Template + +This is a template, [written originally by Tim Pope](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), which appears in the [_Pro Git Book_](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project). + ## Contributing Any kind of help would be appreciated. Example of topics that you can help me with: @@ -202,3 +205,4 @@ Any kind of help would be appreciated. Example of topics that you can help me wi - [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/) - [Pro Git Book - Commit guidelines](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines) +- [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)

我们可以使用git add -p只暂存我们想要的补丁片段,而无需改动已经写好的代码。这在"把一次大改动拆分成多个小提交"或"对特定改动执行 reset/checkout"时非常有用。当选择s拆分时,交互界面如下:

Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]? s Split into 2 hunks.
hunk 1
@@ -186,7 +186,6 @@ `` # Bad (mixes English and Portuguese) ababab Usa o InventoryBackendPool para recuperar o backend de estoque -efefef Add `use` method to Credit model cdcdcd Agora vai `` Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?
hunk 2
@@ -190,6 +189,10 @@ `` cdcdcd Agora vai `` +### Template + +This is a template, [written originally by Tim Pope](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), which appears in the [_Pro Git Book_](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project). + ## Contributing Any kind of help would be appreciated. Example of topics that you can help me with: Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]?
hunk 3
@@ -202,3 +205,4 @@ Any kind of help would be appreciated. Example of topics that you can help me wi - [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/) - [Pro Git Book - Commit guidelines](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines) +- [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)

交互提示中的字母含义:y暂存当前 hunk、n跳过、q退出、a暂存本文件所有剩余 hunk、d跳过本文件剩余 hunk、s进一步拆分当前 hunk、e手动编辑 hunk。同样的-p模式也适用于git checkout -p(放弃部分改动)与git reset -p(从暂存区部分撤出),三者共同构成对 diff 的精细控制能力。

进阶主题:面向开源协作的提交规范

英文主文档(README.md)中还有两个与提交信息密切相关的进阶主题,这里一并补充。

PR 消息与 cover letter 的撰写

大多数开发者在 GitHub、GitLab 等平台上以 Pull Request 形式提交变更,而内核开发者等通过邮件发送补丁的人群则称之为 cover letter(封面信)。无论哪种形式,一封好的 PR 消息 / cover letter 应当为一组相关提交提供概括、背景与上下文,帮助维护者理解"为什么这些改动要放在一起呈现",从而更有效地"推销"你的提交序列。对于小规模改动(单个或少量提交),可以直接把第一个提交当作 cover letter——例如 GitHub 默认就用第一个提交作为 PR 消息。一封高质量 cover letter 通常包含:整体改动及其动机的描述、理解这些改动所需的背景信息、解决方案与实现思路的拆解、可能出问题的注意事项(caveats)、以及超出当前提交集范围的未来增强方向。

Signed-off-by 与 DCO 提交签名

许多开源项目要求贡献者签署代码并遵循相应规范,典型代表是Developer Certificate of Origin(DCO,开发者来源证书)——Linux 基金会、云原生计算基金会(CNCF)等组织的项目普遍要求遵守。这意味着你需要使用真实姓名(即能标识你本人的名字,不一定是法定姓名,但应避免假名)并在提交上签名:

# 仅对当前仓库生效 git config --local user.name "Jane Doe" git config --local user.email "janedoe@janedoe.com" # 或全局生效 git config --global user.name "Jane Doe" git config --global user.email "janedoe@janedoe.com"

提交时加上-s标志,Git 会自动在提交信息中追加一行Signed-off-by: ...:

git commit -s

除了 DCO 签名行,还可以使用GPG(GNU Privacy Guard)对提交做加密签名,向他人证明"这个提交确实由你创建、且在到达他人之前未被篡改"。Git 通过user.signingkey与commit.gpgsign配置配合 GPG 密钥使用;更进一步,可以借助pinentry等工具接入 YubiKey、Touch ID 等硬件层面的物理安全层。

如何在仓库中继续深入

  • 通读英文权威版本 README.md,其中包含葡萄牙语版缺失的更详尽章节(如自我指涉措辞、个人化语言、PR 消息、签名规范);
  • 阅读简体中文版 README_zh-CN.md 与繁体中文版 README_zh-TW.md,对照不同语言版本之间的信息一致性;
  • 查看 CONTRIBUTING.md 了解贡献规范——值得注意的是,该文档本身要求"提交信息、issue 与 PR 使用英文,并遵循本指南的最佳实践",堪称"用指南指导自身仓库"的闭环示例;
  • 通过 CODEOWNERS 了解各语言版本的维护者归属,通过 LICENSE 确认许可条款。

此外,文档还推荐了两个趣味延伸:whatthecommit.com(随机生成无意义提交信息的娱乐站点,反向印证好信息的重要性)与 gitmoji(用 emoji 标注提交类型的社区约定)。其正文引用的主要思想来源包括 Chris Beams 的《How to Write a Git Commit Message》、Tim Pope 的《A Note About Git Commit Messages》、《Pro Git Book》中的提交规范与改写历史章节,以及 Atlassian 的《Merging vs. Rebasing》教程。

结语

从"commit 是快照"这个底层模型出发,到祈使句、首字母大写、正文写"为什么"、50/72 字符限制、语言一致性、标准模板这一整套可落地的编写规范,再到 rebase、squash、cherry-pick、交互式暂存与签名机制这一系列历史整理工具,commit-messages-guide 用一份文档串联起了提交信息写作的完整链路。它的核心理念值得反复强调:提交信息是给未来的维护者(包括未来的自己)写的,它描述的应当是变更的意图与原因,而不只是变更本身。把这套实践内化为习惯,你的提交历史就会从"流水账"变成一份高质量的项目演进档案。

  • 教程
  • 版本控制

【免费下载链接】commit-messages-guide

A guide to understand the importance of commit messages and how to write them well

项目地址:https://gitcode.com/gh_mirrors/co/commit-messages-guide
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询