ship-it
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseShip It
Ship It
Input: a PR number or URL, or nothing — then use the current branch's PR ( with no
argument resolves it). If the current branch has no PR yet, push it and open one with
(maintainer branch only), then continue. Goal: the PR merged with every code-review finding fixed and CI green.
gh pr viewgh pr create输入:PR 编号或 URL,或者不提供任何输入——此时使用当前 branch 的 PR( 不带参数即可解析)。如果当前 branch 还没有 PR,则先 push 该分支,再使用 创建一个(仅限 maintainer branch),然后继续。目标:合并 PR,修复所有 code-review 发现项,并让 CI 通过。
gh pr viewgh pr create0b. A figure in the description, when the change has a shape
0b. 当变更具有可直观呈现的形态时,在描述中添加图示
If the PR changes how something flows — a request path, a background job, what a feature does step
by step — a picture explains it faster than the diff does. Use the skill: write a JSON
spec, render one animated SVG, and put it at the top of the PR description. It plays in the
description with no upload and no click.
figureReference it by commit SHA, not branch name, or the image dies when the branch is deleted at
merge: . If the SVG is not part
of the change itself, don't commit it to the repo — render it, commit it on the PR branch only if it
belongs there, and otherwise keep the description's image pinned to the commit that carried it.
https://raw.githubusercontent.com/<owner>/<repo>/<sha>/<path>.svgSkip it for a fix with no shape: a one-line guard, a dependency bump, a typo.
如果 PR 改变了某项内容的流转方式——请求路径、后台作业、功能的逐步执行过程——那么图示比 diff 更快地解释清楚。使用 skill:编写 JSON spec,渲染一张动画 SVG,并放在 PR 描述顶部。它会直接在描述中播放,无需上传,也无需点击。
figure必须通过 commit SHA 引用,而不能使用 branch name,否则合并时删除 branch 后,图片就会失效:。如果 SVG 本身不属于此次变更,不要将其提交到仓库——先渲染;只有当它确实属于此次变更时,才提交到 PR branch;否则,让描述中的图片继续固定到承载该 SVG 的 commit 上。
https://raw.githubusercontent.com/<owner>/<repo>/<sha>/<path>.svg对于没有可展示形态的修复,跳过此步骤:一行 guard、依赖版本升级、拼写错误。
0. Blocker rule (applies at every step)
0. Blocker 规则(适用于每一步)
A blocker is a finding whose fix would go against the PR's goal — the code-review
principles say the thing the PR sets out to do is wrong (e.g. the PR's whole point is a raw-SQL
handler, a new advisory lock, a tuple-returning API, a test that asserts via SQL, dropping bank
scoping), or fixing it would mean rewriting/removing the feature rather than polishing it.
On a blocker: stop immediately. Don't push, don't merge, don't partially fix. Tell the user
what the PR is trying to do, which principle it conflicts with (quote the section),
and the options you see — then ask for confirmation with AskUserQuestion. Resume only on an explicit answer.
code-reviewEverything else (must fix, should fix, nits) is not a blocker: fix it all.
blocker 是指这样一类审查发现:如果修复它,就会违背 PR 的目标——code-review 原则认为 PR 试图实现的事情本身就是错误的(例如,PR 的全部目的就是 raw-SQL handler、新 advisory lock、返回 tuple 的 API、通过 SQL 进行断言的测试,或取消 bank scoping),或者修复它意味着重写或删除该功能,而不是对其进行打磨。
遇到 blocker:立即停止。不要 push,不要 merge,也不要只修复一部分。向用户说明 PR 想做什么、它与哪条原则冲突(引用 部分),并列出可选方案——然后通过 AskUserQuestion 请求确认。只有收到明确答复后才能继续。
code-review其他所有项(must fix、should fix、nits)都不属于 blocker:全部修复。
1. Load the PR
1. 加载 PR
Read the PR — title, body, linked issue, diff — so you know its goal; the blocker rule depends on it.
If it's , rebase onto first: a conflicting PR gets zero CI runs, silently.
CONFLICTINGorigin/mainWork out whether the author is a maintainer (write/maintain/admin on the repo, e.g. ).
nicoloboschi读取 PR——标题、正文、关联 issue 和 diff——以了解其目标;blocker 规则依赖于这些信息。如果状态为 ,先将 branch rebase 到 :处于冲突状态的 PR 不会触发任何 CI run,而且不会给出提示。
CONFLICTINGorigin/main判断作者是否为 maintainer(在仓库中拥有 write/maintain/admin 权限,例如 )。
nicoloboschi2. Check out the PR branch
2. 检出 PR branch
Work in the current worktree — don't create a new worktree or clone. Before switching, note its
state (current branch/commit and any uncommitted changes) so you can restore it in step 6; set
uncommitted work aside with a WIP commit or a uniquely tagged stash (never a bare — the
stash stack is shared across worktrees). Then check out the PR's branch (skip if you're already on
it). On current-branch input, ask the user if uncommitted work isn't obviously part of the PR.
git stash- Maintainer PR: fixes are committed and pushed to this branch — the PR's own head. Never open a separate fix PR.
- External (fork) PR: push to the fork branch too if maintainers can modify it; otherwise stop and ask the user how to proceed (follow-up PR vs. ask the contributor).
Before every push, make sure the author hasn't pushed meanwhile. If they have, read their new
commits and rebase yours onto their head — never force-push over work you haven't read.
在 current worktree 中工作——不要创建新的 worktree 或 clone。切换前,记录其状态(当前 branch/commit 以及所有未提交更改),以便在步骤 6 恢复;使用 WIP commit 或带唯一标签的 stash 暂存未提交工作(绝不要使用普通的 ——stash 栈在不同 worktree 间共享)。然后切换到 PR 的 branch(如果已经在该 branch 上则跳过)。当输入指向当前 branch 时,如果未提交工作显然不属于该 PR,请询问用户。
git stash- **Maintainer PR:**修复会提交并 push 到这个 branch——即 PR 自己的 head。绝不要另开 fix PR。
- **外部(fork)PR:**如果 maintainers 可以修改 fork branch,也将修复 push 到该 branch;否则停止并询问用户应如何继续(另开后续 PR,还是请贡献者处理)。
每次 push 前,都要确认作者在此期间没有 push。如果作者已经 push,请读取其新 commits,并将你的 commits rebase 到其 head 上——绝不要 force-push 覆盖你尚未阅读的改动。
3. Review
3. 审查
Read and follow the repo's code-review skill at its absolute path,
( = ), against the PR's changes
(base = ). Collect every finding: must fix, should fix, and nits.
<repo>/.claude/skills/code-review/SKILL.md<repo>git rev-parse --show-toplevelorigin/<baseRefName>Classify each against step 0. Any blocker → stop and ask.
按绝对路径 ( = )读取并遵循仓库的 code-review skill,并针对 PR 的变更进行审查(base = )。收集每一项发现:must fix、should fix 和 nits。
<repo>/.claude/skills/code-review/SKILL.md<repo>git rev-parse --show-toplevelorigin/<baseRefName>依据步骤 0 对每项发现进行分类。任何 blocker → 停止并询问用户。
4. Apply ALL fixes
4. 应用所有修复
- Fix every finding, not just the must-fixes. Stay in the PR's scope — don't refactor neighbouring code the review didn't flag.
- Run and the tests covering the touched code (see CLAUDE.md for commands). Regenerate OpenAPI/clients/docs-skill if the change requires it.
./scripts/hooks/lint.sh - Loop until clean. One review pass is never enough: fixes introduce new findings, and the
review only sees what the last pass changed. So repeat — review → fix everything → review again —
until a full pass returns zero findings of any severity (must fix, should fix, nits). Don't stop at "only nits left", don't stop because the last pass found fewer things, and don't declare done on a pass you didn't actually re-run. The only early exit is a blocker (step 0) → stop and ask.
code-review - Commit with a message that lists what was fixed, then push to the PR branch.
Don't post a review comment on a maintainer's PR — findings go in the chat reply and the commit
message. On an external PR, one short comment summarising the fixes you pushed is fine.
- 修复每一项发现,而不只是 must-fix。保持改动在 PR 范围内——不要重构审查未标记的相邻代码。
- 运行 ,并运行覆盖已修改代码的测试(命令见 CLAUDE.md)。如果变更需要,重新生成 OpenAPI、clients 和 docs-skill。
./scripts/hooks/lint.sh - **循环直到干净。**一轮 review 永远不够:修复会引入新的发现,而 review 只能看到上一轮实际改动的部分。因此重复执行——review → 修复全部问题 → 再次 review——直到完整的一轮 对任何严重级别(must fix、should fix、nits)都返回零发现。不要在“只剩 nits”时停止,不要因为最后一轮发现变少就停止,也不要把未实际重新运行的一轮 review 当作完成。唯一的提前退出条件是 blocker(步骤 0)→ 停止并询问用户。
code-review - 使用列明修复内容的 message 进行 commit,然后 push 到 PR branch。
不要在 maintainer 的 PR 上发布 review comment——发现项应放在聊天回复和 commit message 中。对于外部 PR,可以发布一条简短 comment,概述你 push 的修复。
5. Wait for CI green
5. 等待 CI 通过
The repo has no required status checks: merges immediately, and
reports only the checks registered so far (a lone early Strix check reads as
"green"). Gate on the CI workflow run for the pushed head SHA:
gh pr merge --autogh pr checksbash
SHA=$(gh pr view <N> --json headRefOid --jq .headRefOid)
gh run list --branch <headRefName> --workflow CI --json databaseId,status,conclusion,headSha \
| jq --arg s "$SHA" 'map(select(.headSha==$s)) | .[0] // empty'No run yet → keep waiting (give up and report after ~15 min with no run). Once , judge
per job (): zero . If the PR touches the API/engine, ,
, and the LLM acceptance matrix must be , not ; for changes outside
those paths the change filter skips them legitimately. The oracle-client jobs are known-flaky and may
be — ignore those.
completedgh run view <id> --json jobsfailuretest-api (1..3/3)Core LLM testssuccessskippedcancelledFork PRs skip and the LLM jobs (no secrets). Run the full suite on an upstream branch
before merging — merging to main runs no CI at all:
test-apibash
git push origin HEAD:ci/pr-<N>-verify
gh workflow run CI --ref ci/pr-<N>-verify # exactly ONCE — a second dispatch cancels the firstA failure caused by the PR/fixes → fix, push, back to step 5. A known flake (check the job log isn't
touching the PR's code) → once the run has completed.
If CI still fails for reasons you can't attribute, stop and report — don't merge red.
gh run rerun <id> --failed仓库没有必需的 status checks: 会立即合并,而 只报告目前已注册的 checks(单独一个早期 Strix check 会显示为“green”)。必须以针对所 push 的 head SHA 运行的 CI workflow run 作为门禁:
gh pr merge --autogh pr checksbash
SHA=$(gh pr view <N> --json headRefOid --jq .headRefOid)
gh run list --branch <headRefName> --workflow CI --json databaseId,status,conclusion,headSha \
| jq --arg s "$SHA" 'map(select(.headSha==$s)) | .[0] // empty'尚未出现 run → 继续等待(如果约 15 分钟仍无 run,则放弃并报告)。run 完成后,按 job 逐一判断():不得出现 。如果 PR 触及 API/engine,、 和 LLM acceptance matrix 必须为 ,不能为 ;对于这些路径之外的变更,变更过滤器跳过它们属于正常情况。oracle-client jobs 已知可能 flaky,也可能会被 ——忽略这些 jobs。
gh run view <id> --json jobsfailuretest-api (1..3/3)Core LLM testssuccessskippedcancelledFork PR 会跳过 和 LLM jobs(因为没有 secrets)。合并前在 upstream branch 上运行完整测试套件——合并到 main 不会运行任何 CI:
test-apibash
git push origin HEAD:ci/pr-<N>-verify
gh workflow run CI --ref ci/pr-<N>-verify # exactly ONCE — a second dispatch cancels the first如果 failure 是由 PR 或修复导致的 → 修复、push,然后返回步骤 5。如果是已知 flake(检查 job log 未涉及 PR 代码)→ 在 run 完成后使用 重跑一次。如果 CI 仍因无法归因的原因失败,停止并报告——不要在 CI 失败时合并。
gh run rerun <id> --failed6. Restore the worktree, then merge
6. 恢复 worktree,然后合并
First restore the worktree to how you found it: switch back to the original branch/commit and
re-apply any work you set aside (undo the WIP commit / apply-then-drop your tagged stash). Do the
same if you stop early on a blocker or failure. Restoring first also keeps from
trying to check out , which another worktree may hold.
--delete-branchmainbash
gh pr merge <N> --squash --delete-branch
git push origin --delete ci/pr-<N>-verify # if you created itReport: PR link, the findings fixed (one line each), anything deliberately left, and the CI run
that gated the merge.
先将 worktree 恢复到发现它时的状态:切回原始 branch/commit,并重新应用此前暂存的工作(撤销 WIP commit,或应用后删除带标签的 stash)。如果因 blocker 或 failure 提前停止,也执行同样操作。先恢复还有助于避免 尝试 checkout ,因为另一个 worktree 可能正持有该 branch。
--delete-branchmainbash
gh pr merge <N> --squash --delete-branch
git push origin --delete ci/pr-<N>-verify # if you created it报告:PR 链接、已修复的发现(每项一行)、有意保留的内容,以及作为合并门禁的 CI run。
Note on gh pr edit
gh pr edit关于 gh pr edit
的说明
gh pr editIt fails on this repo — a GraphQL "Projects (classic)" deprecation aborts it and nothing changes,
silently. To edit a description use the REST API instead:
bash
gh api -X PATCH repos/<owner>/<repo>/pulls/<N> -F body=@body.md它在此仓库上会失败——GraphQL 的 “Projects (classic)” 弃用错误会中止操作,而且不会发生任何更改,不会给出提示。要编辑描述,请改用 REST API:
bash
gh api -X PATCH repos/<owner>/<repo>/pulls/<N> -F body=@body.md