关于 github-release
面向单包 GitHub 仓库的发布管理 Skill。它使用 `gh` 和 `git` 分析变更与标签、建议 SemVer 版本、更新变更日志,并准备发布分支和拉取请求。
主要功能
- 01发布前只读检查
- 02基于差异分类变更
- 03建议 SemVer 版本
- 04起草并更新变更日志
- 05发布分支与 PR 工作流
适用场景
- 01评估库版本发布前的代码变更
- 02准备版本变更日志和发布 PR
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill github-release安装后在 Claude Code 中输入/github-release确认已加载。
附带文件references/semver-rules.mdreferences/commit-classification.md
详细介绍
GitHub Release Skill
该技能为单包 GitHub 仓库自动化完整的发布工作流,
涵盖从分析到编写变更日志以及创建 PR 的全过程。它仅依赖
gh (GitHub CLI) 和 git,无需其他工具。
步骤 1 - 4 是只读侦察,在步骤 5 确认版本号之前, 不会向仓库写入任何内容。
何时使用此技能
当用户想要在 GitHub 仓库上发布新版本、发布新 release、递增版本号、 创建发布分支、生成变更日志或创建发布 PR 时,均可使用此技能。 即使用户只是随口说“我们发个新版本吧”或“该发布了”,也应触发。
前置条件
以下示例包含 Bash 和 PowerShell 两种版本;Windows 用户应优先使用 PowerShell 代码块。
开始之前,请验证环境:
gh auth status # must be authenticated
gh repo view --json nameWithOwner # must be inside a GitHub repo
git status # working tree should be clean
如果任何检查失败,请停止并告知用户需要修复什么,然后再继续。
然后向用户提出一个问题:
“你的库面向公众的源代码位于哪个目录? (例如
src/、lib/、pkg/——用于将 diff 聚焦在消费者 实际看到的内容上。按 Enter 扫描整个仓库。)”
将答案保存为 PUBLIC_PATH。如果为空,则 PUBLIC_PATH 为 .(仓库根目录)。
无论何种情况,都从所有 diff 中排除以下路径:tests/、test/、spec/、
__tests__/、docs/、*.lock、*-lock.json、*.sum、生成的文件
(带有“do not edit”头部注释的文件)以及构建产物。
9 步发布工作流
按顺序完成每一步。向用户展示你即将运行的命令及其 输出。仅在明确注明时才暂停并请求确认。
步骤 1 - 确保 main 是最新的
git checkout main
git pull origin main
暂时停留在 main 上。发布分支在步骤 5 确认版本号之后
才会创建。
步骤 2 - 获取最新的版本标签
为什么不使用
gh release list? GitHub Releases 是 Git 标签之上的可选层。许多仓库使用git tag打标签,而从未创建 GitHub Release, 因此即使存在版本标签,gh release list也可能返回空。直接从 git 读取标签才是可靠的真相来源。
# Fetch all tags from remote to ensure local view is current
git fetch --tags
# Find the latest version tag, sorted semantically
# --sort=-version:refname handles 1.10.0 > 1.9.0 correctly (unlike alphabetical)
PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+' | head -1)
echo "Latest tag: $PREV_TAG"
# Fetch all tags from remote to ensure local view is current
git fetch --tags
# Find the latest version tag, sorted semantically
# --sort=-version:refname handles 1.10.0 > 1.9.0 correctly (unlike alphabetical)
$prevTag = git tag --sort='-version:refname' | `
Select-String '^[vV]?\d+\.\d+\.\d+' | `
Select-Object -First 1 -ExpandProperty Line
if ($prevTag) {
$prevSha = git rev-list -n 1 $prevTag
} else {
$prevSha = git rev-list --max-parents=0 HEAD
}
Write-Output "Latest tag: $prevTag"
然后验证该标签存在于远程(而不仅是本地):
git ls-remote --tags origin | grep "refs/tags/$PREV_TAG$"
如果远程检查没有任何返回,请警告用户该标签似乎仅存在于本地 且尚未被推送——他们可能希望在继续之前先推送它。
PREV_TAG是所找到的标签名原文(例如v1.4.2)。在进行算术运算时 去掉任何前导v;在命名时保留它。- 如果完全不存在任何标签,将
PREV_TAG视为(none),将PREV_SHA设为 第一个提交,并将新版本默认为1.0.0(跳过步骤 4 的版本号逻辑; 直接进入步骤 5)。 - 如果标签未指向真实提交(孤立标签),则回退到
git rev-list --max-parents=0 HEAD并警告用户。
PREV_SHA=$(git rev-list -n 1 "$PREV_TAG" 2>/dev/null || git rev-list --max-parents=0 HEAD)
步骤 3 - 分析自上次发布以来发生了什么变化
此步骤使用两个互补信号。代码 diff 是主要的真相来源; 提交信息提供有关意图的辅助上下文。
3a - 代码差异(主要信号)
# Focused diff on the public source path, excluding noise
git diff "$PREV_SHA"..HEAD -- "$PUBLIC_PATH" \
':(exclude)tests/' ':(exclude)test/' ':(exclude)spec/' \
':(exclude)__tests__/' ':(exclude)docs/' \
':(exclude)*.lock' ':(exclude)*-lock.json' ':(exclude)*.sum'
# Focused diff on the public source path, excluding noise
git diff "$($prevSha)..HEAD" -- $publicPath `
':(exclude)tests/' ':(exclude)test/' ':(exclude)spec/' `
':(exclude)__tests__/' ':(exclude)docs/' `
':(exclude)*.lock' ':(exclude)*-lock.json' ':(exclude)*.sum'
阅读完整的 diff 输出。对于每个变更文件,识别:
- 被移除的符号 - 之前存在而现在消失的函数、类、方法、常量、导出名称。? MAJOR 的强信号。
- 变更的签名 - 在两个版本中都存在但参数、返回类型或抛出的错误不同的函数。? MAJOR 的强信号。
- 新增导出符号 - 之前不存在的公共函数、类、常量。? MINOR 的信号。
- 仅内部变更 - 不触及任何公共接口的修改(私有辅助函数、未导出函数、算法内部实现)。? PATCH。
- 缺陷修复 - 对可证明错误的逻辑进行纠正(例如差一错误、空值检查、错误条件),且不改变公共 API。? PATCH。
如果 diff 非常大(数千行),先运行统计摘要,以确定优先完整阅读哪些文件:
git diff "$PREV_SHA"..HEAD --stat -- "$PUBLIC_PATH"
将详细阅读的重点放在变更最多的文件,以及名称暗示其定义公共接口的文件(例如 index.*、api.*、exports.*、public.*、mod.*、__init__.*)。
3b - 提交日志(次要信号)
git log "$PREV_SHA"..HEAD --oneline --no-merges
用它来:
- 理解仅凭 diff 无法自解释的代码变更背后的意图(例如被标记为安全修复的一行改动)。
- 捕捉可能位于
PUBLIC_PATH之外的路径但仍对用户可见的变更(例如cmd/目录中的命令行标志变更)。 - 为仅凭代码无法说明完整背景的变更日志条目补充上下文。
有关消息模式到变更类型的映射,请参阅 references/commit-classification.md。
3 - 协调两个信号
当信号一致时 ? 有把握地采用该分类。
当信号冲突时 ? 优先采用代码差异。示例:
- 提交信息说
fix: typo,但 diff 显示移除了一个公共方法 ? 视为 MAJOR。 - 提交信息说
feat: new API,但 diff 只触及私有内部实现 ? 视为 PATCH。 - 提交信息说
chore: refactor,但 diff 新增了导出符号 ? 视为 MINOR。
记录你注意到的任何冲突 - 在 Step 6 的变更日志审查期间向用户标记它们。
Step 4 - 确定下一个 SemVer 版本
将以下规则应用于你在 Step 3 中的分析(完整规则见 references/semver-rules.md):
| 条件 | 版本提升 |
|---|---|
| 对公共 API 的任何破坏性变更(移除、签名变更、行为变更) | MAJOR |
| 新增导出符号或功能,无破坏性变更 | MINOR |
| 仅缺陷修复、性能改进、安全修复、文档、杂务 | PATCH |
当一次发布包含多种情况时,最高优先级胜出:
MAJOR > MINOR > PATCH。
计算 NEXT_VERSION:
- 将
PREV_TAG拆分为MAJOR.MINOR.PATCH整数。 - 应用相应的版本提升。
- 格式化为
vMAJOR.MINOR.PATCH。
向用户展示建议的版本,并附上简要理由,引用具体的代码发现,而不仅仅是提交信息。示例:
"我建议 v2.1.0。diff 显示
src/client.go中有两个新增导出函数(NewClient和WithTimeout),且没有移除或更改任何现有公共符号。提交信息也印证了这是功能新增。"
询问:"这个版本看起来对吗,还是你想调整它?" 在继续之前等待确认。
Step 5 - 创建发布分支
既然版本已确认,从一开始就用正确的名称创建分支:
git checkout -b release/vX.Y.Z
git push -u origin release/vX.Y.Z
第 6 步 - 更新 CHANGELOG.md
读取现有的 CHANGELOG.md(如果不存在则创建)。严格遵循
Keep a Changelog 格式。
在文件顶部插入的结构(紧接在 # Changelog 标题下方):
## [X.Y.Z] - YYYY-MM-DD
### Added
- ...
### Changed
- ...
### Deprecated
- ...
### Removed
- ...
### Fixed
- ...
### Security
- ...
规则:
- 使用今天的日期,格式为
YYYY-MM-DD。 - 省略没有任何条目的部分 - 不要留下空标题。
- 条目应使用从用户视角出发的通俗英文撰写,主要依据
代码 diff 所展示的内容,辅以提交信息的上下文。
好:"Added
WithTimeoutoption to HTTP client constructor." 差:"feat: add timeout cfg param" - 将发现映射到各部分:
- 新增导出符号 ? Added
- 破坏性移除 ? Removed
- 对现有 API 的破坏性变更 ? Changed(将其标记为破坏性)
- Bug/逻辑修复、性能 ? Fixed
- 安全修复 ? Security
- 内部重构、文档、杂项、测试 ? 除非用户可见,否则省略
- 如果提交信息透露了仅凭代码 diff 无法传达的意图 (例如伪装成一行改动的安全修复),请在 changelog 条目中纳入该上下文。
- 同时更新文件底部的 diff 链接:
[X.Y.Z]: https://github.com/OWNER/REPO/compare/vPREV...vNEXT
在写入磁盘之前,先向用户展示拟议的 changelog 部分。 如果在第 3c 步中发现了任何信号冲突,请在此处标记出来,以便用户核实。 询问:"这个 changelog 看起来准确吗?有没有需要添加、删除或改写的条目?" 采纳反馈,然后写入磁盘。
第 7 步 - 提交并推送
git add CHANGELOG.md
git commit -m "chore: release vX.Y.Z"
git push origin release/vX.Y.Z
在继续之前,确认推送成功。
第 8 步 - 打开 Pull Request
?? 重要: 始终使用 --body-file 来传递 PR 正文文本,切勿使用带内联文本的 --body。
像 \n 这样的内联转义序列不会被 PowerShell 解释为换行符,而会在
PR 中显示为字面文本。使用文件可确保正确的 markdown 格式。
gh pr create \
--base main \
--head release/vX.Y.Z \
--title "Release vX.Y.Z" \
--body "$(cat <<'EOF'
## Release vX.Y.Z
This PR prepares the **vX.Y.Z** release.
### What's included
### Checklist
- [ ] Changelog reviewed
- [ ] Version bump verified
- [ ] CI passing
After merging, create the tag on the merge commit:
\`\`\`
git tag vX.Y.Z <merge-commit-sha>
git push origin vX.Y.Z
\`\`\`
EOF
)"
# Create PR body using here-string (preserves actual newlines, not escape sequences)
$prBody = @"
## Release vX.Y.Z
This PR prepares the **vX.Y.Z** release.
### What's included
<paste changelog here>
### Checklist
- [ ] Changelog reviewed
- [ ] Version bump verified
- [ ] CI passing
After merging, create the tag on the merge commit:
```
git tag vX.Y.Z <merge-commit-sha>
git push origin vX.Y.Z
```
"@
# Write to file and use --body-file (do NOT use inline --body with escape sequences)
$prBody | Out-File -FilePath release_pr_body.md -Encoding utf8 -NoNewline
gh pr create --base main --head release/vX.Y.Z --title "Release vX.Y.Z" --body-file release_pr_body.md
将 changelog 部分粘贴到 PR 正文的 "What's included" 块中(或留一个占位符供人工审核)。
第 9 步 - 移交给用户
告诉用户:
发布 PR 已打开!??
新版本:vX.Y.Z
一旦 PR 被审核并合并,你需要自己创建标签,在 合并提交上:
git tag vX.Y.Z <merge-commit-sha> git push origin vX.Y.Z然后前往 GitHub Releases,从该标签发布 release。你可以直接将 changelog 部分复制到 release 说明中。
错误处理
| 情况 | 该怎么办 |
|---|---|
gh auth status 失败 | 停止;告诉用户运行 gh auth login |
| 不在 git 仓库内 | 停止;告诉用户 cd 进入他们的仓库 |
| 工作区有未提交的更改 | 警告;询问他们是想 stash 还是中止 |
| 自上个标签以来没有任何提交 | 告诉用户没有可发布的内容 |
| 标签存在但不指向任何提交 | 使用第一个提交作为 diff 基准;警告用户 |
| 最新标签在本地存在但不在远程 | 警告用户;询问他们是想先推送标签还是继续 |
PUBLIC_PATH 的 diff 为空但存在提交 | 警告;所有更改可能都是内部的;询问他们是否仍要继续 |
git push 失败(例如受保护分支规则) | 原样报告错误;建议他们检查分支保护设置 |
PowerShell 中的故障排除
- 如果某个在本地可以运行的命令打印出 gh 用法或将子命令视为单独的 token,请确保你 调用的是 PATH 上的 gh.exe(Get-Command gh),并避免传递未展开的嵌套替换;请使用上面的 PowerShell 模式。
- 推荐测试:gh --version;git fetch --tags;运行 PowerShell 片段以设置 $prevTag 并运行 git diff --name-only $prevSha..HEAD -- src/
限制
- 需要安装并认证
ghCLI。 - 需要 git 标签来确定当前版本。
参考文件
references/semver-rules.md- 扩展的 SemVer 决策规则和边界情况references/commit-classification.md- 将提交信息分类为变更类型的启发式方法