mcpField
S
ship

ship

github.com/jwh3times其他015 次安装今天更新
代码仓库

关于 ship

ship 是一项技能,可将已完成的分支经过检查、更新变更日志并提交为拉取请求。它为维护者提供与版本发布相关的步骤,并在合并前停止。

主要功能

  1. 01检查仓库与分支前提
  2. 02评估发布影响和版本
  3. 03按版本更新变更日志
  4. 04按范围刷新文档
  5. 05推送前运行快速检查
  6. 06创建或更新拉取请求

适用场景

  1. 01为已完成的分支准备评审
  2. 02记录合并对应的发布说明
  3. 03提交 PR 前核对仓库步骤
  4. 04刷新现有分支的拉取请求

MCP 相关

当 `gh` CLI 不可用时,技能要求使用等效的 GitHub MCP 操作访问仓库并处理拉取请求。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jwh3times/skills --skill ship

安装后在 Claude Code 中输入/ship确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

settings/
human-follow-up.md
issue-tracker.md
README.md
releases.md
ship.md
workspace.md

详细介绍

Ship

将当前分支从“代码已完成”推进到“PR 已创建且可通过 CI”,并在变更日志中注明此次合并实际会生成的版本。

开始时宣布:“我正在使用 ship 技能为此分支创建 PR。”

在 bash(Windows 上使用 Git Bash)中运行 shell 片段。如果 gh 不可用,请使用等效的 GitHub MCP 操作:CLI 缺失会改变操作界面,不会改变步骤或完成标准。

ship 在“PR 已创建”时停止。它绝不会合并、推送到 main、强制推送,也不会运行完整测试套件:这些由 CI 负责,在此处运行会拖慢此技能。

0. 设置

此技能会读取 docs/agents/workspace.md、docs/agents/issue-tracker.md、docs/agents/human-follow-up.md、docs/agents/releases.md 和 docs/agents/ship.md。按照 .agents/skills/ship/settings/README.md 的说明读取这些文件,并补全缺失的文件;定义文件位于其旁边。此处解析每个 discover: 值一次,并在下文重复使用。

使用 Scheme: none 时,跳过所有标记为 (release) 的步骤。

1. 前置条件——任一条件不满足时停止

  • 当前分支不是 main。 必须在分支上工作。若当前位于 main,停止并提出创建一个按 Issue link 分支命名模式命名的分支(若其值为 none,则使用 <type>/<slug>)。

  • 工作区干净。 git status --porcelain 除步骤 0 刚写入且将纳入本次运行提交的设置文件外,不应输出任何内容。否则停止并询问是否提交现有内容;绝不擅自提交。得到答复后,从此步骤重新开始。之后暂存的每项更改都必须由本次运行产生。

  • 可访问 GitHub。 gh auth status 成功,或 GitHub MCP 能访问此仓库。

  • 配套工作区状态正常。 如果已设置 Private companion 且其检出目录存在,则运行 Workspace status command:配套工作区必须干净,且与其上游既不超前也不落后。检出目录不存在也是有效状态;需报告。

  • 与 main 同步。

    git fetch -q --tags origin
    git merge-base --is-ancestor origin/main HEAD && echo current || echo behind
    

    如果当前分支落后,提出现在运行 git merge origin/main,并与用户一起解决冲突。绝不变基已推送的分支。

始终使用 origin/main,绝不使用本地 main:过时的本地 main 会悄然扩大差异范围,把已合并的工作也纳入其中;而只获取了当前分支的克隆则没有本地 main。

2. 评估发布影响(release)

阅读整个分支,而不只是最新提交:

base="$(git merge-base origin/main HEAD)"
git diff --stat "$base"..HEAD
git log --format='%s%n%b' "$base"..HEAD
git diff "$base"..HEAD

stat 和日志只是索引。请先阅读差异,以及受其影响的测试和文档,再作出判断。按对本项目的影响,选择其中最高级别:

  • Major — 现有的公开行为、API、URL、持久化数据格式、配置、部署契约或既定用户工作流变得不兼容,用户必须迁移。对于 0.y 系列,不兼容变更属于 minor,除非该分支有意发布 1.0.0。
  • Minor — 向后兼容的功能或行为的实质性扩展,或有意进行的平台或工具链代际变更,从而提高受支持的基线。
  • Build — 修复(包括安全修复)、依赖维护、重构、测试、文档、工具:不增加功能,也不提高基线。

判断本项目的契约,而不是依赖项的版本号。发布元数据和生成的镜像不能作为依据。对于 Scheme: per-merge,Unreleased 的累计内容也计入评估。用户要求的级别仍需评估;如果评估结果不同,请同时说明两者并询问用户。

记录 Release level: <major|minor|build> — <one-sentence rationale>。步骤 9 和 10 使用这一整行内容。

应用该级别。 基线取最新 v* 标签(忽略 Skipped tags Ignore 模式)与 origin/main 上的 Version file(git show "origin/main:<file>")两者中的较高版本。

  • Build — Version file 保持为 origin/main 上的值。如果该分支在没有发布意图的情况下修改了它,请恢复。
  • Minor — 目标系列为基线版本的 <major>.<minor + 1>.0。
  • Major — 目标系列为 <major + 1>.0.0。

对于 major 或 minor,请先遵循 Ask before bumping,然后使用确切的目标版本运行 Bump command,这样重新运行时会落在相同的值,而不会再递增一次。检查版本文件及其旁边的任何 lockfile 是否一致。如果分支已有该目标版本,则保留;如果分支已有不同系列的版本,则表示这是有意递增的:替换前先询问。

3. 计算目标版本(release)

  • per-merge — 首先确认 origin/main 上最新的合并已打标签:

    git tag --points-at origin/main -l 'v*'
    

    输出为空,表示刚合并的提交尚未完成标签工作流;此时下一个版本会重复已占用的版本号。请等待工作流完成,再次获取标签并重新检查;如果工作流完成后仍未打标签,请询问用户。然后运行 Next-version command。它会输出纯 SemVer,这是唯一可信来源:切勿自行计算 build 编号。

    检查是否已有其他打开的 PR 占用了该版本:

    gh pr list --state open --json number,headRefName --jq '.[] | "\(.number) \(.headRefName)"'
    gh pr diff <number> -- CHANGELOG.md | grep '^+## \['
    

    如果有,请在报告中注明该 PR:后合并的 PR 会在下一次 ship 时重新编号。

  • cut-on-line — build 没有确切的目标版本:下一个标签会分配该版本,无论是工作流为每次合并打标签,还是维护者为某个发行版打标签;而且,其他合并可能先落地。已确认的 major 或 minor,其目标版本是步骤 2 中的新系列。

4. 回填跳过的标签(发布)

仅适用于 Scheme: per-merge 和 Skipped tags: backfill。列出没有对应章节的已发布版本。 按原样运行;标签会打印为 v1.1.5,章节则是 1.1.5,所以人工直接比较原始列表时, 会误以为每个标签都缺失:

comm -23 \
  <(git tag -l 'v*' | sed -nE 's/^v([0-9]+\.[0-9]+\.[0-9]+)$/\1/p' | sort) \
  <(sed -nE 's/^## \[([0-9]+\.[0-9]+\.[0-9]+)\].*/\1/p' CHANGELOG.md | sort)

排除匹配 Ignore 模式的版本。剩下的每个版本都对应一次未写入章节的合并——可能是 依赖机器人提交的 PR,也可能是在 Web UI 中创建的 PR。按日期为每个版本在相应位置添加 章节,最新的放在最前面。将 version 设为对应版本后,读取其标签;标签指向合并提交, 因此合并分支是它的第二个父提交:

git log -1 --format='%cs' "v$version"                  # the section's date
git log --format='%s%n%b' "v$version^1..v$version^2"   # what landed
git diff "v$version^1" "v$version" --stat              # manifests and lockfiles it changed
git log -1 --format=%an "v$version^2"                  # dependabot[bot] for a bot PR

保持客观:注明软件包名称和版本,并将仅修改锁文件的变更称为传递性变更。只有在第二个 父提交的作者是机器人时,才将变更归因于机器人:合并提交的作者是点击 Merge 的人。如果 不存在 ^2(即采用了 squash 或 fast-forward),则读取标签自身的提交。

如果使用 Skipped tags: roll up,不要为每个跳过的标签单独创建章节;这些变更会并入下 一个新增的章节。

5. 更新文档

以 fix 模式运行 docs-updater skill,仅针对此分支的差异,不要进行全面审查——如果 运行环境支持子 Agent,则在子 Agent 中运行,并要求其遵循 .agents/skills/docs-updater/SKILL.md;否则由你自行遵循。子 Agent 无法询问用户,因此请 先在此处完成其设置,方法是遵循其步骤 0。

range="$(git merge-base origin/main HEAD)..HEAD"

告知它有哪些变更及原因、它是由 ship 在尚未合并的分支上调用的,以及此 skill 会写入 变更日志和 Version file。它会保留未提交的编辑,并返回步骤 6 中发现的人工操作,以及 合并后需要执行的任何 wiki 搜索(Follow-up wiki,或 wiki 中的 Doc map 条目)。 配套编辑应在其自身仓库中提交,绝不能在当前仓库中提交:如果 Companion commit policy 为 commit 或 ship,则提交并推送;如果为 ask,则展示差异并先询问。无论哪种情况, 都要运行其 Before committing 检查。

6. 人工后续操作

在 PR 开启前,针对此分支留下的每项必需人工操作(包括 docs-updater 返回的操作),运行 .agents/skills/ship/settings/human-follow-up.md 中的 ## Procedure。应合并整理,不要 重复创建;重新发布时,沿用已有记录。后续操作不能只记录在变更日志或 PR 正文中。其链接 应放在报告和私有记录中,绝不能放在公开 PR 中。

7. 编写变更日志(发布)

记录用户可见的行为及其影响,并根据差异推导,而不是记录提交历史。使用文件已有的标题(Keep a Changelog:Added、Changed、Deprecated、Removed、Fixed、Security,以及文件中新增的任何标题),每个章节只出现一次,并保持原有语气。日期使用今天的日期,格式为 YYYY-MM-DD。

幂等。 列出此分支新增的章节:

git diff origin/main...HEAD -- CHANGELOG.md | grep '^+## \['

此处列出的章节是此分支之前一次 ship 所添加的:在原处重写,绝不再叠加一个。此分支添加到 Unreleased 的条目也要以同样方式重写。

  • per-merge — 在 ## [Unreleased] 正下方插入 ## [<target>] - <date>,其中包含此分支的条目以及 Unreleased 中累积的所有内容;将 Unreleased 重置为 Unreleased 占位符。如果此分支的章节因另一项 PR 先合并而使用了较旧的版本号,请将该章节重新编号为目标版本。然后合并 origin/main:他们的章节位于相同位置,因此解决 CHANGELOG.md 冲突时要保留两者,并让最新版本排在前面,然后回到第 3 步——他们的合并创建了一个标签,因此目标版本又变了。
  • cut-on-line、build — 将条目添加到 Unreleased 下,替换其占位符。不添加带日期的章节,也不编辑 Version file。
  • cut-on-line、已确认的 major 或 minor — 将条目添加到 Unreleased 下,把其中的全部内容移入 ## [<target>] - <date>,并恢复占位符。如果之前一次 ship 已经完成了版本切分,则在该章节内重写此分支的条目;绝不要让它们同时出现在切分线上下。

引用链接。 如果文件以链接页脚结尾,请遵循其中条目的格式,保持链接一致:[Unreleased] 从最新版本指向 HEAD,每个新增或重新编号的章节(包括补填的章节)都要添加自己的链接,并按从新到旧的顺序排列。

运行 Changelog check。如果不匹配,它会指出合并实际创建的版本:使用该版本重新执行此步骤。

8. 快速检查——任何一项失败都不得推送

按顺序在对应文件夹中运行每条 Fast checks。只有在没有相关路径发生变化时,才跳过条件检查(git diff --name-only origin/main...HEAD)。这些检查要在文档和变更日志编辑完成后运行,因为格式化工具和 linter 也会检查这些文件。

如果任何检查失败,请停止并报告;不要推送。提供该检查对应的修复命令。修复命令写入文件后,从头重新运行整个检查列表:基于未格式化源文件生成的镜像,在源文件格式化后会再次过时。无法在此处运行的检查(缺少服务、缺少密钥)要在报告中注明,留待 CI 运行。

然后运行 docs/agents/ship.md 中的 Hook: before PR。将其发现的问题写入报告,并在说明要求时写入 PR 正文。

9. 提交、推送并创建或更新 PR

仅当 git status --porcelain 显示有更改时才提交;再次发布但没有新内容时,不要创建空提交。由于步骤 1 已确认工作树干净,因此暂存所有内容是安全的,而且配套仓库已被忽略,绝不会被暂存:

git add -A
git commit -m "<Release commit message, with the real version>"
git push -u origin "$(git branch --show-current)"

推送被拒绝意味着远程仓库有此检出版本没有的提交:停止并报告。绝不要强制推送。

gh pr list --head "$(git branch --show-current)" --state open --json number,url
  • 没有 PR → gh pr create --base main。
  • 已有 PR → 使用 gh pr edit <number> 刷新 PR 正文。绝不要再创建第二个 PR。

将正文写入临时文件,并传入 --body-file。如果仓库有 PR 模板(.github/pull_request_template.md 或 PULL_REQUEST_TEMPLATE.md),请根据变更日志条目和差异填写模板。加入步骤 2 中的 Release level: 行;使用 per-merge 时,还要写明此次合并将生成的版本。

议题链接,仅当设置不是 none 时适用。正文以链接行开头,放在模板预留的位置:

  • 根据分支的 Branch pattern 获取 N,并读取议题: gh issue view <N> --json title,state,labels,body。
  • 如果此 PR 会完成议题,使用结束行(Closes #N);如果它是一个保持开放的规范中的一部分,则使用切片行(Part of #N)。每个已完成的议题都要有自己的关键词:GitHub 只会链接 Closes #1 and #2 中的第一个议题。
  • 分支没有编号时:如果用户豁免了此流程,则使用 Waiver line;若类型为 Exempt,则不添加链接行。
  • 如果分支编号与议题不一致,或无法确定是完成议题还是仅为其中一部分,创建 PR 前先询问。刷新正文时保留其链接行。仅在标题中写编号不会产生链接。

如果 PR 正文没有链接行且类型并非豁免,或已设置 Board 但关联议题不在该看板上,请发出警告,但不要阻止流程。Private issue repository 中的议题绝不能在公开 PR 正文、提交消息或公开议题中提及;合并后手动关闭。

此步骤写入的任何公开内容都不得包含私有仓库名称、链接、看板编号或配套仓库详情。

10. 报告

  • PR URL 和分支。
  • Release level: 行及其依据;此次合并将生成的版本(per-merge)、新版本线(cut-on-line 切分),或说明构建版本将由下一个标签指定。指出声称使用相同版本的其他 PR,并说明再次发布时该章节会重新编号。
  • 文档刷新所做的更改、写入的变更日志条目,以及回填的任何章节。如果 docs-updater 需要在合并后搜索 wiki,请说明:下一次 end-session 会执行此操作。
  • 人工跟进事项:已验证的议题和 wiki 链接、未发布的内容及其原因,或说明已无待办事项。
  • 快速检查结果、留给 CI 的检查、Hook: before PR 的发现,以及议题链接警告。
  • 配套仓库:未配置,或已同步且状态干净,并说明是否创建了配套仓库提交。绝不要将尚未合并的 PR 描述为已在配套仓库发布。
  • 步骤 0 中写入的设置文件。

明确说明:完整测试套件会在 CI 中运行,而非在此处运行;分支仅经过快速检查验证。

评论

支持 Markdown