mcpField
G
github-release

github-release

github.com/github开发40.6k749 次安装1 天前更新
代码仓库

关于 github-release

面向单包 GitHub 仓库的发布管理 Skill。它使用 `gh` 和 `git` 分析变更与标签、建议 SemVer 版本、更新变更日志,并准备发布分支和拉取请求。

主要功能

  1. 01发布前只读检查
  2. 02基于差异分类变更
  3. 03建议 SemVer 版本
  4. 04起草并更新变更日志
  5. 05发布分支与 PR 工作流

适用场景

  1. 01评估库版本发布前的代码变更
  2. 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 输出。对于每个变更文件,识别:

  1. 被移除的符号 - 之前存在而现在消失的函数、类、方法、常量、导出名称。? MAJOR 的强信号。
  2. 变更的签名 - 在两个版本中都存在但参数、返回类型或抛出的错误不同的函数。? MAJOR 的强信号。
  3. 新增导出符号 - 之前不存在的公共函数、类、常量。? MINOR 的信号。
  4. 仅内部变更 - 不触及任何公共接口的修改(私有辅助函数、未导出函数、算法内部实现)。? PATCH。
  5. 缺陷修复 - 对可证明错误的逻辑进行纠正(例如差一错误、空值检查、错误条件),且不改变公共 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 WithTimeout option 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/

限制

  • 需要安装并认证 gh CLI。
  • 需要 git 标签来确定当前版本。

参考文件

  • references/semver-rules.md - 扩展的 SemVer 决策规则和边界情况
  • references/commit-classification.md - 将提交信息分类为变更类型的启发式方法

评论

支持 Markdown