首页
/ Black 更新日志全景解析:CalVer 版本体系、CHANGES.md 结构与稳定性政策的协同机制

Black 更新日志全景解析:CalVer 版本体系、CHANGES.md 结构与稳定性政策的协同机制

2026-09-05 13:12:34作者:薛曦旖Francesca

Black(PSF 旗下"毫不妥协的 Python 代码格式化器")的版本演进全部沉淀在仓库根目录的 CHANGES.md 中,而 docs/change_log.md 则是将其渲染为官方文档站"Change Log"页面的入口。本文以这份变更日志为主体,结合仓库中的发布脚本、贡献文档与稳定性政策文档,讲清楚 Black 的版本号如何生成、变更日志各小节如何组织与核对、以及如何基于稳定性政策正确解读每一条条目——读完后你将能独立完成:在升级 Black 前定位相关行为变化、判断某项样式改动属于稳定风格还是预览风格、并按项目规范编写合格的 changelog 条目。

docs/change_log.md:一个指向 CHANGES.md 的文档入口

docs/change_log.md 本身只有 3 行,全部内容是一个 Sphinx MyST 的 include 指令:

```{include} ../CHANGES.md
```

这意味着文档站的 Change Log 页面并不维护独立内容,而是直接内嵌仓库根目录的 CHANGES.md(当前约 2500 行)。这一设计带来两点重要含义:

  • 单一事实来源:changelog 只有一处可写位置。任何"文档里说的版本变化"与 CHANGES.md 不一致的情况,都以 CHANGES.md 为准;
  • 链接锚点规范:正因为该文件会被渲染进文档站,条目标题才统一采用 ## Version X.Y.Z 的形式(26.5.0 的 Documentation 小节记录了这个决定,即"在 changelog 中使用 Version X.Y.Z 标题以便在 ReadTheDocs 上获得稳定的永久链接锚点"),读者可以通过文档站的稳定锚点直接定位某个版本。

CHANGES.md 的骨架:Unreleased 模板与版本小节

打开 CHANGES.md 可以看到固定的两层结构。

顶层:## Unreleased## Version YY.M.N

文件开头(第 3 行)是 ## Unreleased 区块,其下带有一段 HTML 模板注释,提示 PR 作者:

Please include the PR number in the changelog entry, not the issue number

条目必须引用 PR 编号而非 issue 编号。每条变更以 PR 编号收尾,例如当前 Unreleased 中的:

  • Add support for NO_COLOR environment variable to disable ANSI output (#5129)
  • --line-ranges no longer inserts an empty line after a docstring when the range covers only the docstring itself (#5312)

Unreleased 之下是逐版本向下的历史记录,从最近的 ## Version 26.5.1(约第 215 行)一直追溯到 2018 年的 ## Version 18.3a0。发布流程文档 docs/contributing/release_process.md 说明了这条时间线的维护方式:发布 GitHub Release 后,post release 工作流会打开一个 new-changelog PR,把空白的 Unreleased 模板重新加回 changelog(该 PR 故意不自动合并,以便出问题时重新切发布),并通过 update-stable 任务把 stable 分支强推到最新 tag。

每个版本下的标准小节

从 Unreleased 模板和既有版本条目可以归纳出 Black 的标准小节集合:

小节 含义
### Highlights 本版本最重要的、破坏性最大的变化(模板注释提示"把特别重大或破坏性的变化放这里")
### Stable style 影响 Black 稳定代码样式的改动
### Preview style 影响 --preview 预览样式的改动
### Configuration 配置方式的变化(pyproject.toml、命令行、缓存等)
### Parser 解析器或版本自动检测的变化
### Performance 性能改进(近年条目显著增多,Unreleased 中即有二十余条)
### Output 终端输出与错误消息变化
### _Blackd_ 服务端组件 blackd 的改动(如 25.11.0 中"实现了 BlackDClient 客户端")
### Integrations Docker、GitHub Actions、pre-commit、编辑器集成
### Documentation 文档与政策的重大变化

个别版本还会出现临时小节,例如 24.10.0 的 ### Caching。空小节在切版时会被 scripts/release.py 自动清除。

一个典型的"Highlights 叙事"示例来自 25.12.0:

Black no longer supports running with Python 3.9 (#4842)

这类运行环境变化被放在 Highlights 而非普通小节,因为它直接决定用户能否安装运行,阅读 changelog 时应优先扫读每个版本的 Highlights。

版本号规范:CalVer 与 YY.M.N

发布文档 docs/contributing/release_process.md 明确:Black 遵循 CalVer(日历版本)标准,格式为 YY.M.N:

  • YY/M 是发布年份与月份,N 是该月内的第几次发布;
  • 除非当月已有发布,否则 N 应为 0;例如"2026 年 1 月的第一次发布 → 26.1.0";
  • scripts/release.py 会计算这个版本号并打印到 stdout 供复制。

CHANGES.md 的时间线可以直观验证这套体系:早期为 18.3a018.9b0(带预发布后缀),2020 起出现 20.8b0,2021 起改为 21.12b0 这类 beta 后缀,而近期版本(23.7.0 之后)基本是不带后缀的正式号。此外,项目根目录的 action.ymlDockerfile 等发布产物都随该版本号一起更新;25.11.0 的 Packaging 小节就记录了一次"修正发布可执行文件中版本号错误"的热修复(26.5.1 同样修正了发布可执行文件的版本号),可见版本号被广泛嵌入交付物,出错时会单独切 patch 版。

稳定性政策:读懂 Stable style 与 Preview style 分节的关键

changelog 之所以要把"Stable style"与"Preview style"严格分开,背后是 Black 的稳定性政策(见 docs/the_black_code_style/index.md):

  • 若代码已用 Black 格式化过,那么在同一个日历年内的其他版本、使用相同选项再格式化时,输出保持不变。文档中给出的例子是:项目在 2026 年可以安全使用 black ~= 26.0;
  • 每个日历年的第一个版本"可以"包含格式化变化,且应尽量最小化,以纳入新 Python 语法带来的改进;
  • --preview--unstable 两个标志不受该政策约束,输出无稳定保证。

这条政策与 changelog 的运作是联动的:

  1. Stable style 小节 = 政策保护范围。其中既包含 bug 修复(如"修复 # fmt: off 块前注释被误删"),也包含年度风格切换(见下节);
  2. Preview style 小节 = 试验田--preview 的变化不会破坏同一年内的稳定输出承诺;
  3. CI 强制执行:贡献文档 docs/contributing/gauging_changes.md 描述了 diff-shades CI——对每个 PR,除了 preview-new-changes(用 preview 风格跑一批开源项目并给出 diff 摘要)外,还有 assert-no-changes 任务,以稳定风格运行,一旦发现格式化输出变化就会让 CI 失败,从而"确保同一年内代码不会被反反复复重新格式化"。这正是稳定性政策在工程上的落地点。

年度风格切换在 changelog 中的样子

日历年的第一个版本会把上一年的 preview 特性"转正"为新的稳定风格,在 changelog 中表现为 Highlights 里的大段列举。从 CHANGES.md 可以读到三次完整实例:

  • 23.1.0 — 2023 稳定风格:纳入前一年 preview 的十余项变化(空行处理、冗余括号移除、隐式字符串拼接输出等),并首次"从 pyproject.toml 自动推断受支持的 Python 版本";
  • 24.1.0 — 2024 稳定风格:列举了约二十项转正条目(如 if-else 表达式加括号、长赋值优先在右侧断行、模块 docstring 后强制换行),同时在 Preview style 小节引入了新的 --unstable 风格与 --enable-unstable-feature 标志,把"已知有问题的特性"从 preview 中隔离出去;
  • 25.1.0 — 2025 稳定风格:转正列表包含"Unicode 转义十六进制统一小写"、"一致地为带类型参数添加尾随逗号"、"case 块 if 守卫中的冗余括号处理"等,并列出当年新增、此前从未发布的两项("移除独占列表项的括号"、"泛型函数定义的更优雅折行")。

对读者的实用含义:如果项目锁定 black ~= 25.0,则 25.x 各版本间样式保证不变;而当 26.1.0 发布时,应重新检查一次 25.1.0 之后的 Preview/Highlights 记录,判断年度切换对本仓库 diff 的影响。

版本时间线:从 18.9b0 到 26.5.1 的关键节点

不必逐条阅读 2500 行,按里程碑扫描 CHANGES.md 就能把握 Black 的能力演进。以下节点均可在文件中直接定位核对:

版本 关键变化 小节
18.9b0 早期形态:magic trailing comma、docstring 重缩进、彩色 diff、black-primer 回归工具 早期条目
19.10b0 PEP 572 海象运算符、PEP 570 位置-only 参数、black -c 命令行格式化
20.8b0 显式尾随逗号重新实现、--force-exclude# fmt: off 修复、基于 Hypothesis 的属性模糊测试
23.1.0 2023 稳定风格;从 pyproject.toml 推断 target 版本 Highlights
23.7.0 移除 Python 3.7 运行时支持(仍支持格式化 3.7 代码);BLACK_NUM_WORKERS 环境变量;新增 PEP 695 语法支持 Highlights / Configuration / Parser
23.11.0 新增 --line-ranges 命令,只格式化指定行范围 Highlights
24.1.0 2024 稳定风格;引入 --unstable--enable-unstable-feature;移除长期弃用的 --experimental-string-processing Highlights / Configuration
24.3.0 修复 Black 首个 CVE(CVE-2024-21503):docstring 中大量前导制表符导致的灾难性性能问题;同时强化 AST 安全检查 Highlights / Performance
24.4.1 支持 Python 3.12 的 PEP 701 f-string 新语法;支持 PEP 696 类型参数默认值 Highlights / Parser
24.10.0 官方测试 Python 3.13 并提供 mypyc 编译 wheel;明确拒绝 Python 3.12.5(上游内存安全问题),要求 3.12.6 或 3.12.4 Highlights
25.11.0 支持 Python 3.14 基础语法与 PEP 750 t-string;--no-cache 配置项;blackd 客户端实现 Highlights / Configuration
25.12.0 不再支持 Python 3.9 运行 Highlights
26.5.0 支持 Python 3.15(含 PEP 798 推导式解包、PEP 810 懒加载导入);解析失败返回 HTTP 400 而非 500(blackd) Highlights
26.5.1 / Unreleased 修复 t-string docstring 误判、# fmt: on 前空行保留、NO_COLOR 支持、大量针对 # fmt: skip/大括号扫描路径的性能优化 各小节

几个值得注意的模式:

  • 安全与兼容性条目集中在 Highlights:如 24.3.0 的 CVE、24.10.0 对 Python 3.12.5 的禁用提示(因上游内存问题会导致 Black 的 AST 安全检查失败,文档建议改用 3.12.6 或 3.12.4)。如果你的部署环境涉及这些 Python 版本,应先于样式条目处理这类信息;
  • Unreleased 中的 Performance 小节反映了当前开发重心:近二十条几乎全部是"不再重新扫描整棵树/整行/整个子节点"类算法优化(如 max_delimiter_priority_in_atomis_line_short_enoughappend_leaves 中避免全量重扫),并标注了各自的 PR 编号;
  • 条目粒度:每条都是"行为 + 场景示例 + PR 编号"的三元组,例如 24.2.0 Configuration 中"pyproject.toml 缺少 tool.black 节时不再作为项目根依据……monorepo 用户若需保持旧行为,在旧 pyproject.toml 中添加空的 [tool.black] 即可"——这类带迁移建议的条目对升级决策最有价值。

从 changelog 反查仓库:发布流程如何自动维护这份日志

changelog 的可信度很大程度来自发布自动化。docs/contributing/release_process.md 给出的完整流程如下,均可对照仓库文件验证:

  1. 确定版本号:CalVer YY.M.N,由 python3 scripts/release.py 计算并输出(脚本仅在 Python 3.12+ 上测试);
  2. 核对小节归属:确认自上次发布以来的 changelog 条目没有放错小节,文档建议运行 git diff origin/stable CHANGES.mdstable 分支比对——stable 分支正是发布后由 update-stable 工作流强推到最新 tag 的;
  3. 提交发布 PR:python3 scripts/release.py 会自动完成大部分工作:把 ## Unreleased 标题替换为版本号、删除空小节、更新 docs/integrations/source_version_control.mddocs/usage_and_configuration/the_basics.md 中对最新版本的引用;失败时可手工编辑,模板可由脚本直接复制;
  4. 等 CI 全绿后创建 GitHub Release:tag 目标为 main,标题即版本号,描述粘贴该版本的原始 changelog Markdown;
  5. 发布后:post release 工作流中 new-changelog 重新挂回 Unreleased 模板,update-stable 对齐 stable 分支;
  6. 发布节奏:目标是每 1~2 个月发一次 main 上的一切;除非有严重回归,每月至多一次;理想情况下不跳过 1 月发布,因为按稳定性政策"新年第一个版本可改稳定风格",把样式变化收敛在 1 月能保持可预期。

此外,diff-shades 的 CI 集成(docs/contributing/gauging_changes.md)在 PR 上自动对比两个 Black 修订版对一批开源项目的格式化差异:PR 触发时基线为"PR 基分支最新提交",目标为"合入 main 后的 PR 提交";对 main 的推送则以"PyPI 最新版"为基线。其 HTML/JSON 工件与 PR 评论摘要构成了 changelog 之外、可量化核对"某 PR 到底改了什么格式"的第二证据链。

实战:如何高效使用这份更新日志

  • 升级前评估:先读目标版本 Highlights 中的运行环境条款(如 25.12.0 移除 Python 3.9 运行支持、24.10.0 拒绝 3.12.5),再对照 Stable style 判断是否涉及年度风格切换(23.1.0/24.1.0/25.1.0 模式),必要时用 black --check --diff 在分支上验证;
  • 定位行为回归:每条条目都带 PR 编号,从"修复 + 场景 + 编号"的写法可以直接反查对应实现与测试。例如 Unreleased 中"保留 # fmt: on 前紧邻的空行 (#5300)"、"t-string 不再被当作 docstring (#5287)"这类条目,说明当前开发重点在 # fmt: skip/off/on 指令与 Python 3.14+ 新语法(t-string,PEP 750)的边界情况;
  • 核对配置类变化:Configuration 小节记录了可直接迁移的行为,如 Unreleased 中"BLACK_NUM_WORKERS 非法值现在报 usage error 而非崩溃"、"空缓存文件按其他畸形缓存处理"等,对 CI 与容器环境(缓存只读/缺失场景)尤为相关;
  • 遵循规范写条目:贡献时引用 PR 号而非 issue 号、把条目放进正确小节、重大破坏性变化写入 Highlights,并按 docs/contributing/release_process.mddocs/contributing/gauging_changes.md 的流程提交。

小结

Black 的 CHANGES.md 不只是一份流水账,而是 CalVer 版本规范、稳定/预览双风格、年度稳定性政策与 diff-shades CI 共同作用下的产物:Stable style 小节受"同年内输出不变"的政策与 assert-no-changes CI 约束,Preview style 小节承载试验特性并在每年 1 月的版本中批量转正为新的稳定风格,Highlights 则汇总了环境支持与安全事故(CVE)等必须优先阅读的信息。掌握这套结构后,无论是锁定 black ~= 26.0 评估年度风格切换的影响,还是按模板规范撰写一条合格的 changelog 条目,都有了明确的依据与路径。

登录后查看全文
热门项目推荐
相关项目推荐