GreptimeDB 版本发布说明(Release Note / Changelog)生成实战:基于 git cliff 的完整工作流
2026/9/17 20:11:37 网站建设 项目流程

GreptimeDB 版本发布说明(Release Note / Changelog)生成实战:基于 git cliff 的完整工作流

【免费下载链接】greptimedbThe open-source observability database. One columnar engine for metrics, logs, and traces, on object storage.项目地址: https://gitcode.com/GitHub_Trending/gr/greptimedb

导读:本文讲解如何为 GreptimeDB 生成专业、完整、可对外发布的版本变更日志(changelog)。你将掌握从 GitHub token 注入、上一版本判定、git cliff区间选择(minor 与 patch 的拓扑差异)、减去已发布 PR、重建贡献者名单,到人工精选 Highlights、输出文件规范、以及向 docs 仓库提交草稿 PR 的完整链路。文章以仓库内.agents/skills/greptimedb-release-note/SKILL.md为主干,并结合 cliff.toml、.agents/skills/greptimedb-release/SKILL.md 等仓库文件交叉佐证。


1. 概览:一次完整的 GreptimeDB 发版说明生成流程

GreptimeDB 官方仓库(GreptimeTeam/greptimedb)将「生成 changelog」沉淀为独立的 Agent Skill(.agents/skills/greptimedb-release-note/SKILL.md),并配套独立的发版 runbook(.agents/skills/greptimedb-release/SKILL.md,负责打 tag、创建 GitHub Release、触发 CI)。两者分工明确:

  • greptimedb-release-note生成 changelog + 精选 Highlights + 准备 docs 博客 PR
  • greptimedb-release发布新版本(tag + GitHub Release + docs release-note PR)。

整个生成流程的核心工具链为git cliff(配置见仓库根目录的 cliff.toml)与gh(GitHub CLI),外加用于「减去已发布 PR / 重建贡献者名单」的Python 脚本。所有命令都要求在 greptimedb 仓库的 checkout 目录内执行。

整体流程如下:

  1. 注入 GitHub token(供git cliff调 GitHub API 丰富 PR 标题与作者);
  2. 确定上一正式版本(跳过 nightly / rc / beta);
  3. 选定git cliff的版本区间(区分 minor 与 patch 两种拓扑);
  4. 生成原始 changelog,减去已在中间 patch 版本发布过的 PR;
  5. 重新计算New ContributorsAll Contributors
  6. git log交叉验证;
  7. 手工精选 Highlights(含可运行示例)与 Dashboard 小节;
  8. 输出到CHANGELOG-vX.Y.Z.md(不提交);
  9. 生成 docs 仓库博客变体并以 draft PR 提交。

2. 前置条件与远端解析

在开始之前,需要确认以下工具可用:

  • git cliff:changelog 生成器,其配置为仓库根目录的 cliff.toml;
  • gh(GitHub CLI):用于查询 release 列表、读取 release body、调用 API 获取 PR 信息;先执行gh auth status确认已登录;
  • Python:第 3、4 节的「减去已发布 PR」与「重建贡献者名单」步骤需要脚本化处理。

2.1 解析指向官方仓库的 remote

仓库可能同时配置了多个远端,文档统一用<remote>代指指向GreptimeTeam/greptimedb的那个(通常是upstream,直接 clone 时可能是origin)。解析命令:

git remote -v | grep -i 'GreptimeTeam/greptimedb' | awk '{print $1}' | head -1

后续所有涉及gh的操作都显式带上--repo GreptimeTeam/greptimedb,避免误操作 fork 或个人远端。

2.2 了解工具链的组织方式

在仓库中,Agent 技能统一存放在.agents/skills/<skill-name>/SKILL.md(见 .agents/README.md),Codex 会自动从.agents/skills发现技能,Claude Code 则通过指向该目录的符号链接读取。发版说明技能还有配套的 Agent 接口声明(.agents/skills/greptimedb-release-note/agents/openai.yaml),将技能描述为「Generate GreptimeDB release notes」——这说明该技能的核心能力就是三件事:生成 changelog、精选 highlights、准备 docs release-note PR。


3. GitHub token:注入但永不打印

git cliff需要借助 GitHub API 将 commit 丰富为 PR 标题与作者;当涉及数百个 commit 时,没有 token 会触发 API 限流,导致信息不完整(有 token 时仍会运行,只是可能被限流/缺失数据)。

关键原则:token 以内联方式传入,绝不读取或回显 token

GITHUB_TOKEN=$(gh auth token) git cliff ...

另一种方式是让用户通过 env 文件导出GITHUB_TOKEN(同样不要读取其内容)。无论哪种方式,都不得在日志、输出或对话中打印 token 值。


4. 确定上一版本:跳过 nightly、rc 与 beta

从 release 列表中过滤出正式版本号:

gh release list --repo GreptimeTeam/greptimedb

需要忽略的标签形态包括:

  • *-nightly-*:nightly 版本;
  • -rc.*-beta.*:候选发布与测试版;
  • 带构建后缀的标签(如v1.0.0-rc.2-13cdfa9b5-20260325-1774407105)。

重点关注形如vX.Y.Z的正式标签,然后按版本形态确定「上一版本」:

当前要发布的版本上一版本判定规则示例
PatchvX.Y.Z(Z>0)上一版本 =vX.Y.(Z-1)v1.0.2→ 上一版本为v1.0.1
新 minorvX.Y.0上一版本 = 最新的vX.(Y-1).*v1.1.0→ 上一版本为最新v1.0.x;发v1.0.0→ 最大的0.x

务必与用户二次确认这个「上一版本」的判定结果,因为它直接决定后续要减去哪些已发布的 patch PR。


5. 区间选择与拓扑:minor 与 patch 的两种生成路径

这是整个技能中最关键、也最容易出错的环节。核心拓扑事实:

  • minor 标签(如v1.0.0)是main的祖先;
  • patch 标签v1.0.1v1.0.2)位于release/v1.0分支上,不是main的祖先(它们是 cherry-pick,SHA 不同)。

可用如下命令验证某个标签是否为main的祖先:

git merge-base --is-ancestor <tag> <remote>/main

5.1 新 minor(X.Y.0,从 main 切出)

这里有一个容易混淆的要点:git cliff的 base 是上一 minor 的.0标签(如v1.0.0,它是main的祖先),而不是第 4 节确定的「上一版本」(最新的 patch,如v1.0.2)。后者只用于决定要减去哪些 patch PR。

GITHUB_TOKEN=$(gh auth token) git cliff <prev-minor-tag>..<release-commit> --tag vX.Y.0 \ -o /path/CHANGELOG-vX.Y.0.md

其中:

  • base= 上一 minor 标签(如v1.0.0);
  • tip= release commit(release/vX.Y的 tip,通常就是<remote>/main)。

关于 nightly 标签的处理:cliff.toml中配置了ignore_tags正则:

ignore_tags = ".*-nightly-.*|^v[0-9]+\\.[0-9]+\\.[0-9]+(-(alpha|beta|rc)\\.[0-9]+)?-[0-9a-f]{7,}-[0-9]{8}-[0-9]+$"

该正则的作用是:忽略 nightly 标签以及带构建后缀的 release 标签(如v1.0.0-rc.2-13cdfa9b5-20260325-1774407105),使这些区间内的 commit 被折叠进下一个可见 release 区块,而不是生成多余的独立标题。

随后减去中间 patch 版本中已发布的 PR:这些 patch(vX.(Y-1).1.2……)的 main 分支 commit 也落在该区间内,如果不减去会重复列出;而读者关心的是相对最新 patch 的增量。收集 patch release body 中的 PR 集合:

gh release view vX.(Y-1).Z --repo GreptimeTeam/greptimedb | grep -oE 'pull/[0-9]+'

然后删除 changelog 中每个#NNNN落在该集合内的条目。技能明确建议:用一个小型 Python 脚本是可靠方式——匹配以*开头的行中的pull/<n>)

5.2 Patch(X.Y.Z,Z>0,release 分支上的 cherry-pick)

上一 patch 标签是 release 分支的祖先,因此当 cherry-pick 以独立 commit 形式落地时,直接使用普通区间即可:

GITHUB_TOKEN=$(gh auth token) git cliff <prev-patch-tag>..<release-branch-tip> --tag vX.Y.Z -o ...

无需额外减去 PR(分支上只包含新的 cherry-pick)。

5.3 常见场景:squashed pick commit

patch 分支常常是一个单独的 squash commit,形如chore: pick fixes and bump version to vX.Y.Z (#NNNN),此时上述普通区间只会生成一条记录。处理步骤:

第一步:找出被 pick 的 PR,读取 squash commit 信息:

git log -1 --format=%B <release-branch-tip>

其中每一行* fix: ... (#NN)就是一个被 pick 的 PR。

第二步:两种构建方式二选一(patch 通常只有少量 PR,先询问用户偏好):

方式 (a):在main上生成再过滤——让git cliff产出格式正确的条目(标题、作者、分类):

  1. main上按时间顺序定位并排列被 pick PR 的 commit:

    git log --oneline <remote>/main --grep='#NN1' --grep='#NN2' --reverse

    第一行是最早的 pick,最后一行是最新的 pick。

  2. 对覆盖全部被 pick commit 的main区间运行 cliff(base = 最早被 pick commit 的父提交,tip = 最新的 pick),然后只保留被 pick 的#NN条目:

    GITHUB_TOKEN=$(gh auth token) git cliff <oldest-pick>~1..<newest-pick> --tag vX.Y.Z -o /tmp/raw.md

    原始输出中会包含区间内未被 pick的无关联 PR——需要丢弃它们,然后按第 6 节重建贡献者名单。

方式 (b):手工撰写条目——对于小 patch(以及 API/网络不稳定时)是很好的兜底方案。对每个被 pick 的 PR 获取标题与作者:

gh api repos/GreptimeTeam/greptimedb/pulls/<n>

然后手工写出* <title> by [@user] in #NN行和贡献者列表。

兜底原则:无论分支历史多么混乱,统一遵守「识别被 pick 的 PR,只保留这些 PR」的规则。

网络不稳时的补充说明git cliff会从 GitHub API 拉取仓库完整 commit 历史来做作者信息丰富(即使区间很小,也会分页回溯数千个 commit)。连接不稳时可能中途超时;由于它会对分页结果做缓存,直接重跑直到完成即可——每次重试都会从缓存继续。若持续失败,则回退到方式 (b)。


6. 减去 PR 后重建贡献者名单

cliff是在完整区间上计算New Contributors/All Contributors的,因此删除条目后必须根据剩余的 commit 条目重新计算:

  • All Contributors= 从剩余* ... by [@user] ... in [#NN]行中提取的@user有序集合(剔除dependabot[bot]之类的机器人)。
  • New Contributors= 在 All Contributors 基础上,剔除「首次贡献 PR 已被删除」的条目(例如该贡献者唯一落在区间内的 PR 其实已随 patch 发布过)。

这个计算应当放在同一个减去 PR 的脚本中完成,一步到位。

关于贡献者名单的呈现方式,cliff.toml的模板给出了仓库的实际规范:All Contributors按用户名排序并以逗号分隔,且显式跳过dependabot[bot]New Contributors则逐一列出首次贡献者及其 PR 链接。模板中的is_first_timepr_number字段正是上述计算的输出依据。


7. 验证:与 git log 交叉核对

生成完毕后,用git log <base>..<tip>交叉核对结果:

  • 没有已减去 PR 的残留;
  • 没有遗漏真正新增的 PR;
  • 机械性的chore: bump version to vX.Y.Z行可选择性删除(询问用户,有人偏好保留)。

8. 人工精选 Highlights 与 Dashboard 小节

这是从「机械 changelog」升级为「可读 release note」的关键步骤。内容插入在Release date:行之后,并参考历史 release body 的写法(gh release view v1.0.0 --repo GreptimeTeam/greptimedb)。

8.1 Highlights 的写作规范

  • 简短引言:精炼、工程师语气,不用营销形容词;

  • ### 👍 Highlights小节:选择少数、深入的亮点,每条都配一个可运行的示例(SQL 或 TOML 配置);

  • 示例必须经源码/文档验证:阅读 highlight 对应的 PR 以及 docs 仓库(GreptimeTeam/docs,通常本地已 checkout)中的相关文档页,并在以下位置校验语法:

    • docs/reference/sql/*.md
    • config/*.example.toml
    • config/config.md

    在当前仓库中,这些文件的对应物正是 config/config.md 与 config/standalone.example.toml 等配置文件,以及 docs/rfcs 下的 RFC 文档,可作为示例校验的参照。

  • 不提及实现细节、微小功能、未完成或实验性(尚未 ready)的功能;

  • 必须让用户审阅并编辑 highlights,迭代修改

8.2 Dashboard 小节

不要只升级版本号就完事。应阅读随版本捆绑的 dashboard 的 PR(gh release view <ver> --repo GreptimeTeam/dashboard后再看关联 PR),描述对用户可见的变更。当前仓库也内嵌了 dashboard 资源(grafana/dashboards 下含 cluster 与 standalone 的 dashboard JSON 及生成脚本 grafana/scripts/gen-dashboards.sh),可帮助理解 dashboard 变更的形态。


9. 输出规范

将结果写入CHANGELOG-vX.Y.Z.md(标题为# vX.Y.Z,由--tag参数产生),不要提交该文件——发版 runbook 会在 release 与 docs PR 完成后删除它(见 .agents/skills/greptimedb-release/SKILL.md 第 4 节:docs PR 打开后即删除本地CHANGELOG-vX.Y.Z.md)。

9.1 changelog 的模板结构

仓库 cliff.toml 中的 Tera 模板定义了最终 changelog 的完整骨架:

  • 标题# {{ version }}Release date: ...行;
  • Breaking changes区块(按breaking属性过滤,独立成节);
  • 其余 commit 按group_by(attribute="group")分组,组名来自commit_parsers中定义的分组标签:🚀 Features、🐛 Bug Fixes、🚜 Refactor、📚 Documentation、⚡ Performance、🎨 Styling、🧪 Testing、⚙️ Miscellaneous Tasks、🛡️ Security、◀️ Revert;
  • 每条目格式为* {{ pr_title }} by @user in #NN
  • 末尾为New ContributorsAll Contributors两个区块。

模板中几个值得注意的配置点:

conventional_commits = true # 按 Conventional Commits 解析 filter_unconventional = true # 过滤非 conventional commit commit_parsers = [ ... ] # 正则 → 分组映射 protect_breaking_commits = false filter_commits = false # 不过滤未匹配的 commit sort_commits = "oldest" # 组内按新旧排序

其中^chore\(release\): prepare for^chore\(deps.*\)^chore\(pr\)^chore\(pull\)等模式被配置为skip = true,会在生成时直接跳过这些机械 commit。


10. docs 仓库博客变体与 draft PR

发布说明还会以博客形式发布到GreptimeTeam/docs仓库。

10.1 准备工作

  • 询问用户其本地GreptimeTeam/docscheckout 路径;若没有,可提供 clone 方案(git clone git@github.com:GreptimeTeam/docs.git <path>);
  • 文件名为blog/release-X-Y-Z.md(版本号用短横线连接,参考blog/release-1-0-0.md)。

10.2 内容格式

内容 = docs frontmatter + GitHub release body,# vX.Y.Z这个 H1 必须紧跟在 frontmatter 之下。博客 frontmatter 没有title:字段,Docusaurus 会用这个 H1 作为页面标题和侧边栏标签——省略它会导致页面以文件名渲染(如release-1-1-0而非v1.1.0)。

参考模板:

--- keywords: [release, GreptimeDB, changelog, vX.Y.Z] description: GreptimeDB vX.Y.Z Changelog date: YYYY-MM-DD --- # vX.Y.Z Release date: ...

10.3 不打扰 docs 工作区:使用 git worktree

docs 的工作区可能有无关的 WIP——不要动它,用origin/main创建独立的 worktree:

git -C <docs> fetch origin main git -C <docs> worktree add -b chore/X.Y.Z-release-note /tmp/docs-release-note origin/main

10.4 遵循 PR 模板并创建草稿 PR

  • 阅读并遵循当前 docs 仓库的 PR 模板.github/pull_request_template.md),填写所有必需章节,审阅者负责的 checklist 保持未勾选;不要依赖旧模板中硬编码的章节名;
  • 带 sign-off 提交、推送、创建draftPR,然后移除 worktree:
git -C /tmp/docs-release-note add blog/release-X-Y.Z.md git -C /tmp/docs-release-note commit -s -m "docs: add X.Y.Z release note" git -C /tmp/docs-release-note push -u origin chore/X.Y.Z-release-note gh pr create --draft --repo GreptimeTeam/docs --base main --head chore/X.Y.Z-release-note \ --title "docs: add X.Y.Z release note" --body-file <template-filled body> git -C <docs> worktree remove /tmp/docs-release-note

已知坑:如果 token 缺少read:org权限,gh pr edit/create可能报 org-scope 错误。此时改用 REST 直接编辑 body:

gh api repos/GreptimeTeam/docs/pulls/<n> -X PATCH -F body=@body.md

11. 与发版 Runbook 的衔接

生成 changelog 只是完整发布链路的一环。配合 .agents/skills/greptimedb-release/SKILL.md 中的 runbook,完整流程为:

  1. 由版本号推断分支(v1.0.xrelease/v1.0;新 minorX.Y.0main切出);
  2. 校验 Cargo workspace 版本与待发布版本一致;
  3. 用本技能生成并精选 changelog;
  4. gh release create创建 GitHub Release(不要预先创建 tag,创建 release 即创建 tag 并触发 tag-push CI 构建二进制,耗时约数小时;默认以--prerelease标记「构建中」,CI 成功后清除);
  5. 立即打开 docs 草稿 PR(无需等待 CI),然后删除本地 changelog 文件;
  6. CI 构建完成后核对isPrereleaseassets,并按「是否最新版本」决定对latest标记的处理。

12. 小结

GreptimeDB 的 release note 生成是一套高度工程化的流程,核心经验可归纳为:

  • 拓扑优先:先搞清 minor 标签是main祖先、patch 标签在 release 分支上,再决定区间与减除策略;
  • 减除防重复:minor 发布时务必减去中间 patch 已发布的 PR,读者只关心相对最新 patch 的增量;
  • 脚本保可靠:PR 减除与贡献者重建用 Python 脚本实现,避免手工遗漏;
  • 人工精选升华:机械 changelog 之外,用带可运行示例的深度 Highlights 让发布说明真正可读;
  • 工具链纪律:token 只注入不回显、changelog 不提交、docs 工作区用 worktree 隔离、PR 走 draft。

这套流程的所有实现细节均沉淀在仓库的 .agents/skills/greptimedb-release-note/SKILL.md 与根目录 cliff.toml 中,是理解 GreptimeDB 社区发版节奏与工具链的最佳起点。

【免费下载链接】greptimedbThe open-source observability database. One columnar engine for metrics, logs, and traces, on object storage.项目地址: https://gitcode.com/GitHub_Trending/gr/greptimedb

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

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

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

立即咨询