两行 diff 的 README 提交:手动补标题还是上钩子,看这3个信号
截至 2026-10-23 抓取,punkpeye/awesome-mcp-servers 仓库出现一个提交 f225f117f92626e6b7d5d2912746d9269e3d037b。这个仓库从名字看是一个 MCP(模型上下文协议)服务器列表,README 就是用户浏览这些服务器的第一页。提交只做了两件事:在 README 最前面加了一行 # Awesome MCP Servers,再加一个空行。GitHub 显示 1 file changed, 2 additions, 0 deletions。为什么一个只有两行新增的标题改动值得单独看?因为 README 的维护经常分成两种:一种是这种只补一级标题的手动小修,另一种是项目结构、安装说明、软件包描述一旦漂移就没人发现。把这次提交和三种 README 自动更新工具放在一起,能看出什么时候该手动,什么时候该上钩子。
一个只有两行新增的提交
从提交页面的 rich diff 能逐行看到,@@ -1,3 +1,5 @@ 之后,第一处新增是 # Awesome MCP Servers,第二处新增是一个空行。原文件开头原本直接是语言徽章,说明这次提交没有改任何现有徽章、链接或仓库说明,只让原始 Markdown 有了一个明确的 H1。如果你想在本地核对,可以执行:
git show --stat f225f117f92626e6b7d5d2912746d9269e3d037b
执行后把它和提交页上的 2 additions & 0 deletions 对照即可。这里只是给出可复现命令,我没有在本文中声称执行结果。
按 diff 位置看,这行 H1 是加在文件最顶部;至于维护者为什么特地为它提交一次,我只能推断是为了让原始 Markdown 不再只靠 GitHub 页面渲染标题。这个推断不是官方说明。另一个值得注意的点是:这次提交在 1 个文件上只动 2 行,说明即便在大型列表仓库里,README 维护也会细到标题级别。手动补标题不产生额外工具成本,但如果你需要每次同步项目结构,光靠这种细粒度提交不够。
手动补标题很快,结构更新容易过时
更典型的需求是自动更新项目结构。my_readme_updater 1.0.8 的 Pub.dev 发布页(版本时间显示 2024-12-09)把用途说得很直接:一个 Dart 包,在你运行 git commit 时自动更新 README 文件里的项目结构。它依赖两个标记 <!-- BEGIN PROJECT STRUCTURE --> 和 <!-- END PROJECT STRUCTURE -->,只有标记之间的内容由它重写。文档给出的设置命令是:
dart run my_readme_updater --setup
也可以在需要时手动运行 dart run my_readme_updater。文档还提醒:运行前要确保 lib/ 目录下的项目结构正确。这可以理解为:工具不会替你判断结构对不对,它只是把 lib/ 目录的既有状态镜像进 README。这类工具解决的是“项目结构写进 README 后没人再改”的问题。但反过来看,它只负责项目结构这一块,不维护安装步骤、许可证、平台支持等段落。如果 README 的其它部分过时,还是会继续漂移。这个边界是文档机制直接决定的:标记只包住项目结构区。
三类自动更新工具的触发方式
第二类触发来自插件命令。GitHub 仓库 rohitg00/awesome-claude-code-toolkit 里的 doc-forge update-readme 文件(文件时间 2026-02-03)定义的是 /doc-forge:update-readme。它要求先读现有 README,保留自定义内容、徽章和作者写的段落,然后从 package.json、pyproject.toml、Cargo.toml 或 go.mod 里拿项目名、版本、描述,查许可证、入口点,运行 git remote get-url origin 拿仓库 URL,再看 CI 工作流和 Docker 支持,最后生成标题、描述、徽章、安装等段落。它不像 pre-commit 钩子那样每次提交都触发,而是用户主动要求一次文档审计。
第三类来自制品仓库 CLI。docs.acoinfo.com 的更新软件包文档(页面标注更新时间 2025-12-19)给出 armory update-readme [<package-spec>] [--file ./path/to/README.md]。前提是软件包已发布,且待更新 README 的版本已确认发布。如果指定 package-spec 或 --file,两者必须同时给,并且 package-spec 要包含标签或版本;如果都不给,命令会在当前目录找 armory.json 和 README.md 或 README.txt,根据 armory.json 自动更新。命令示例为:
armory update-readme @software_factory/tappas-dev@latest -f @software_factory/tappas-dev/README.md
这条路径与代码仓库无关,它更新的是制品仓库里软件包的描述页,所以触发条件更接近“发布后再修正元数据”,而不是开发中持续同步。
对照表:三种方案分别保护什么
下表里,“保护自定义内容”列来自各文档的直接描述;“适用场景”列是我根据触发方式和依赖环境做的归纳,不是官方定位。
| 工具 | 触发方式 | 写入 README 的内容 | 保护自定义内容 | 适用场景 |
|---|---|---|---|---|
| my_readme_updater 1.0.8 | git commit / pre-commit hook | 项目结构,置于 <!-- BEGIN PROJECT STRUCTURE --> 和 <!-- END PROJECT STRUCTURE --> 之间 |
标记区间内不干预;标记外未说明 | Dart/Flutter 项目 |
doc-forge /update-readme |
插件命令 | 项目元数据、安装、徽章 | 文档明确要求保留现有自定义内容、徽章、作者段落 | 通用项目,能读多种 manifest |
armory update-readme |
制品仓库 CLI | 软件包 README 描述 | 文档未提到保护机制 | 已发布内部制品库 |
这三种方案看似都在“更新 README”,但触发点分别对应提交前、审计时、发布后。选错触发点,就会出现要么开发阶段管不到,要么每次提交都动文档的情况。
自动更新不会告诉你的坑
第一,doc-forge 虽然要求保留自定义段落,但“保留”和“合并”是两回事。比如项目名从 A 改成 B 后,生成的一行安装命令变了,而旧的自定义说明里还写着 A;工具是否自动替换,命令文件里没有说明具体合并规则。这是我对缺失规则的推导,不能当作官方承诺。
第二,my_readme_updater 的 pre-commit 钩子会在每次 commit 前重写 README。如果项目和 README 一起提交,可能出现每次提交都带一个 README 结构变更的噪音提交。如果团队使用 squash merge 可能还好,否则提交历史会变得很难读。这个后果是从钩子机制推出来的,不是包文档直接告诉你的。
第三,acoinfo 的 armory update-readme 前提是软件包已发布,这意味着开发阶段的 README 不能依靠它实时更新;想在提交代码时更新 README,还是要回退到 git 钩子或 CI。这是按文档前提条件得出的边界。
所以,选择哪种方案取决于 README 里哪部分最容易过时。如果只是补标题,像 f225f11 一样手动提交足够;如果是结构,选标记式钩子;如果需要项目完整元数据,选 doc-forge 这类命令;如果制品已发布且要改描述,选制品库 CLI。这不是官方建议,而是我从对比中归出来的选择思路。
参考来源
评论区
登录后可评论。