prkit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

prkit

prkit

Turn the commits on the current branch into a clean GitHub pull request: a title in the repo's commit style, a body that explains what changed and why, and a test plan, all inferred from the real diff, not guessed. Creation goes through the
gh
CLI
, reusing the repo's PR template when one exists.
将当前分支上的提交转换为规范的GitHub拉取请求:符合仓库提交风格的标题、解释「更改内容及原因」的正文,以及测试计划,所有内容均从实际差异中推导而来,而非猜测。创建过程通过
gh
CLI
完成,若仓库存在PR模板则会复用该模板。

When this fires

触发场景

The user wants to open a pull request: "open a PR", "create a pull request", "raise a PR", "submit this for review", "gh pr create". If they only want the PR title and body drafted (not opened), do everything except the final
gh pr create
and print the result instead.
当用户想要打开拉取请求时:比如提及“open a PR”“create a pull request”“raise a PR”“submit this for review”“gh pr create”。如果用户仅希望起草PR标题和正文(而非直接打开),则执行除最终
gh pr create
之外的所有步骤,并将结果打印出来。

Procedure

操作流程

1. Preflight

1. 预检

Confirm the tooling and branch are ready before writing anything:
sh
gh --version        # gh installed?
gh auth status      # authenticated?
git branch --show-current
  • If
    gh
    is missing or unauthenticated, say so and point to
    https://cli.github.com
    /
    gh auth login
    . Don't try to work around it.
  • If
    git branch --show-current
    is empty, stop: detached HEAD needs a branch before a PR can be opened. Offer to create or switch to one.
  • If the current branch is the default branch, stop: a PR needs a feature branch. Offer to create one (
    git switch -c <name>
    ) before continuing, and get the name from gitkit, which owns branch naming, rather than inventing a shape here. Work that traces to an issue gets
    issue-<n>-<slug>
    ; anything else keeps whatever name the repo's convention or the human supplies.
在开始撰写内容前,确认工具和分支已准备就绪:
sh
gh --version        # 是否已安装gh?
gh auth status      # 是否已认证?
git branch --show-current
  • 如果未安装gh或未完成认证,请告知用户并引导至
    https://cli.github.com
    /
    gh auth login
    ,不要尝试其他替代方案。
  • 如果
    git branch --show-current
    返回空值,请停止操作:分离头指针(detached HEAD)状态下需要先创建分支才能打开PR。主动提出为用户创建或切换到合适的分支。
  • 如果当前分支是默认分支,请停止操作:PR需要基于功能分支创建。主动提出先创建分支(
    git switch -c <name>
    ),分支名称需从gitkit获取(gitkit负责分支命名规则),而非自行指定。关联问题的分支命名为
    issue-<n>-<slug>
    ;其他分支则遵循仓库约定或用户提供的名称。

2. Gather context

2. 收集上下文

Get the base branch from gitkit, then read what the branch actually changes; that diff is the raw material for the title and body. Fetch first so every ref below is the real remote state, not a stale local copy:
sh
git fetch origin                                         # refresh remote-tracking refs before anything else
git log origin/<base>..HEAD --format='%s%n%b'            # commits in this PR, with their bodies
git diff origin/<base>...HEAD --stat                     # files touched
Read the full diff (
git diff origin/<base>...HEAD
) only when the commits don't already explain the change.
On a branch built through this workflow they usually do, because commitkit wrote each message from the change itself, so the log is a summary of exactly the material a PR body needs, and re-deriving it from the raw diff produces a worse description at many times the cost. Reach for the full diff when the commit messages are thin or generic (a branch of
wip
and
fix typo
commits, or work that came from outside this workflow), when the stat shows files no commit message accounts for, or when you need a specific detail for the test plan. Skip lockfiles, build output, and vendored directories either way.
gitkit owns base-ref resolution. Ask it for the base rather than re-deriving the ladder here; repos whose default is
develop
or
trunk
are real, and getting this wrong silently produces an empty or enormous diff. Without gitkit,
gh repo view --json defaultBranchRef -q .defaultBranchRef.name
is the authoritative fallback, and ask rather than guess when it can't answer. Re-check the current branch against the base gitkit returns and stop if they match.
Diff against
origin/<base>
(the just-fetched remote tip), not a local
<base>
that may be behind. Otherwise the title, body, and file list are computed against commits that are no longer the merge target.
Use the commits, branch name (e.g.
fix/login-123
), and diff to determine the scope, the type of change, and any issue reference (
#123
,
fixes #123
). If a linked issue clearly matters and you can't find it, ask rather than invent one.
gitkit获取基准分支,然后读取当前分支的实际更改内容;这些差异是生成标题和正文的原始素材。先执行fetch操作,确保后续所有引用都是最新的远程状态,而非本地缓存版本:
sh
git fetch origin                                         # 先刷新远程跟踪引用
git log origin/<base>..HEAD --format='%s%n%b'            # 此PR包含的提交及其正文
git diff origin/<base>...HEAD --stat                     # 涉及的文件列表
仅当提交信息无法清晰说明更改时,才读取完整差异(
git diff origin/<base>...HEAD
。在本工作流创建的分支中,提交信息通常已能清晰说明更改,因为commitkit会根据更改内容生成每个提交信息,因此提交日志恰好包含PR正文所需的全部素材,而从原始差异重新推导往往会生成质量更差的描述,且耗时更长。当提交信息过于简略或通用(如包含
wip
fix typo
的分支,或来自本工作流之外的分支)、文件统计结果显示存在提交信息未提及的文件,或需要为测试计划补充特定细节时,才需要读取完整差异。无论哪种情况,均忽略锁文件、构建输出和第三方依赖目录。
gitkit负责基准引用解析。应向gitkit请求基准分支,而非自行推导;部分仓库的默认分支可能是
develop
trunk
,若此处出错,会导致生成空差异或超大差异。如果没有gitkit,则使用
gh repo view --json defaultBranchRef -q .defaultBranchRef.name
作为权威备选方案;若该命令也无法获取结果,请询问用户而非猜测。重新检查当前分支与gitkit返回的基准分支是否一致,若一致则停止操作。
对比
origin/<base>
(刚获取的远程最新版本)的差异,而非可能落后的本地
<base>
分支。否则,生成的标题、正文和文件列表将基于已不再是合并目标的提交。
利用提交信息、分支名称(如
fix/login-123
)和差异内容确定更改范围、类型以及关联的问题编号(
#123
fixes #123
)。如果存在明确相关的问题但无法找到,请询问用户而非自行编造。

3. Sync with the base branch

3. 与基准分支同步

Before pushing, make sure the branch is up to date with the base tip you just fetched. A PR opened from a stale branch either merges outdated code or lands with GitHub's "This branch has conflicts" banner:
sh
git rev-list --left-right --count origin/<base>...HEAD   # "<behind>\t<ahead>"; left > 0 means behind
  • Behind by zero: nothing to do, so go to Push the branch.
  • Behind: the branch needs
    origin/<base>
    brought in. gitkit owns the sync rule, and it resolves to rebase (
    git rebase origin/<base>
    ), giving the PR a clean diff. Whether that needs an OK first turns on one thing gitkit states in full: an unpublished branch rebases straight through, because nothing outside this machine points at the commits being rewritten; a branch already pushed previews the rebase and its
    --force-with-lease
    together and waits. At PR-open time the branch is usually the former, which is why this step normally runs without a prompt.
  • Rebase conflicts: if the rebase stops on a conflict, stop and surface it. List the conflicted files (
    git diff --name-only --diff-filter=U
    ) and resolve them (or hand them back to the user), then complete the rebase (
    git rebase --continue
    ). Do not push, and do not open the PR, until the working tree is clean and the sync is finished. If the user declines the sync, say the PR may show conflicts and proceed only if they confirm.
Don't re-read the diff after a clean rebase. A rebase replays your commits onto a new base; it doesn't change what they say or do, so the title and body you derived above still describe the branch correctly. The one exception is a rebase you resolved conflicts in, because there you made real edits during the replay, and the resolved result is genuinely different from what you read. Re-read just the files you touched resolving them (
git diff origin/<base>...HEAD -- <paths>
), not the whole branch.
在推送分支前,确保分支已与刚获取的基准分支最新版本同步。从过时分支打开的PR要么合并了旧代码,要么会显示GitHub的「此分支存在冲突」提示:
sh
git rev-list --left-right --count origin/<base>...HEAD   # 返回格式为"<落后提交数>\t<领先提交数>";左侧数值大于0表示落后
  • 落后提交数为0:无需操作,直接进入推送分支步骤。
  • 存在落后提交:需要将
    origin/<base>
    的内容合并到当前分支。gitkit负责同步规则,通常采用**变基(rebase)**方式(
    git rebase origin/<base>
    ),使PR的差异更清晰。是否需要先征得用户同意取决于gitkit的明确规则:未发布的分支可直接变基,因为没有外部引用指向这些提交;已推送的分支则需先预览变基结果及对应的
    --force-with-lease
    操作,等待用户确认。在打开PR时,分支通常属于前者,因此本步骤通常无需提示即可执行。
  • 变基冲突:如果变基过程因冲突停止,请立即停止操作并告知用户。列出冲突文件(
    git diff --name-only --diff-filter=U
    ),协助用户解决冲突(或交由用户自行处理),然后完成变基(
    git rebase --continue
    )。在工作树清理干净且同步完成前,不要推送分支或打开PR。如果用户拒绝同步,请告知用户PR可能会显示冲突,并仅在用户确认后继续操作。
变基完成且无冲突时,无需重新读取差异。变基只是将提交重放到新的基准分支上,不会改变提交的内容或说明,因此之前生成的标题和正文仍能准确描述分支。唯一例外是解决了冲突的变基,因为在解决冲突过程中进行了实际编辑,变基后的结果与之前读取的内容不同。此时只需重新读取解决冲突时修改的文件(
git diff origin/<base>...HEAD -- <paths>
),而非整个分支的差异。

4. Push the branch

4. 推送分支

First, commit any handed-in path. When a caller hands prkit a file that must travel with the branch, most often a QA plan at
docs/qa/qa-<slug>-YYYY-MM-DD.md
, and that file is still uncommitted, commit it here rather than leaving it behind or spawning something else to do it. prkit is already the step that touches git, and it was given the path, so there is nothing to rediscover:
sh
git add <handed-in path> && git commit -m "docs(qa): add manual QA plan for <feature>"
Only a path the caller named. This is not a licence to sweep the working tree: uncommitted work nobody mentioned is still covered by the rule in Notes, so point it out and offer, don't commit it silently.
The remote branch must exist before a PR can point at it:
sh
git push -u origin HEAD
If the branch was rebased (Sync with the base branch) and the remote rejects a normal push, use
git push --force-with-lease
(never bare
--force
). Don't ask again here: a rejected push means the branch was already published, and gitkit's rule covers the rebase and its lease push under a single confirmation taken during the sync. If that OK wasn't given, because the branch looked unpublished and the rejection is the first sign it wasn't, stop and ask then.
首先,提交用户指定的文件路径。当调用者向prkit提供必须随分支一起提交的文件(最常见的是位于
docs/qa/qa-<slug>-YYYY-MM-DD.md
的QA计划)且该文件尚未提交时,需在此处提交,而非遗漏或调用其他工具处理。prkit已经在操作git,且已获取该路径,无需额外确认:
sh
git add <handed-in path> && git commit -m "docs(qa): add manual QA plan for <feature>"
仅提交用户明确指定的路径。这并不意味着可以随意提交工作树中的所有未提交内容:未提及的未提交工作仍需遵循注意事项中的规则,需告知用户并主动提出协助提交,而非静默提交。
远程分支必须存在才能创建指向它的PR:
sh
git push -u origin HEAD
如果分支已执行变基(与基准分支同步)且远程拒绝普通推送,请使用
git push --force-with-lease
(切勿使用裸
--force
)。此处无需再次询问用户:推送被拒绝说明分支已发布,gitkit的规则已在同步步骤中涵盖了变基及带lease的推送操作,并已获得一次确认。如果未获得确认(例如分支看似未发布,但推送被拒绝才发现已发布),则停止操作并询问用户。

5. Write the title and body

5. 撰写标题和正文

  • Title: one line, imperative, in the repo's commit style (match
    git log
    , often Conventional Commits like
    feat(auth): add SSO login
    ). No trailing period.
  • Body: if
    .github/pull_request_template.md
    (or
    PULL_REQUEST_TEMPLATE.md
    ) exists, read it and fill it in exactly, matching its sections and checkboxes. Otherwise use: a one-paragraph Summary of what changed and why, a Changes bullet list, and a Test plan (how it was verified, or checkboxes for what to run). Reference the issue in the body (
    Closes #123
    ) when there is one.
  • 标题:单行,祈使语气,符合仓库的提交风格(匹配
    git log
    ,通常采用约定式提交,如
    feat(auth): add SSO login
    )。末尾无句号。
  • 正文:如果存在
    .github/pull_request_template.md
    (或
    PULL_REQUEST_TEMPLATE.md
    ),请读取该模板并严格按照模板填写,匹配其章节和复选框。否则使用以下结构:一段摘要说明更改内容及原因,一个更改内容项目符号列表,以及测试计划(验证方式或待执行的复选框)。如果存在关联问题,请在正文中引用(
    Closes #123
    )。

6. Embed proof artifacts (if present)

6. 嵌入验证工件(若存在)

This step is optional and runs only when a verifykit proof bundle exists. verifykit leaves a dated bundle at
docs/verify/verify-<slug>-YYYY-MM-DD/
(slug = the linked issue number, else the feature slug) with a ready-to-embed
proof.md
. If more than one matches, use the newest creation date; if multiple bundles share that date, ask which run to use. Splice the selected proof into the body under a Proof section. The images are already published to a hidden
refs/verify-assets/*
ref with SHA-pinned raw URLs that render inline, so there's no upload work here; just embed the fragment as-is. If no bundle exists, skip this entirely and open the PR exactly as before. If a bundle exists but its
proof.md
points at local paths (verifykit couldn't publish, e.g. on a private repo), don't embed dead links: add a short note listing the local artifact paths for manual attachment instead.
本步骤为可选步骤,仅当存在verifykit验证包时执行。verifykit会在
docs/verify/verify-<slug>-YYYY-MM-DD/
路径下生成带日期的验证包(slug为关联问题编号,若无则为功能slug),其中包含可直接嵌入的
proof.md
。如果存在多个匹配的验证包,请使用最新创建的版本;如果多个验证包创建日期相同,请询问用户使用哪一个。将选中的验证内容插入到正文的**验证(Proof)**章节下。图片已发布到隐藏的
refs/verify-assets/*
引用中,使用SHA固定的原始URL可直接在线显示,因此无需上传操作;只需将片段原样嵌入即可。如果不存在验证包,则完全跳过本步骤,按原有流程打开PR。如果存在验证包但
proof.md
指向本地路径(verifykit无法发布,例如私有仓库),请勿嵌入无效链接:只需添加简短说明,列出本地工件路径供手动上传。

7. Create or update the PR

7. 创建或更新PR

First check for an existing PR on this branch so you update instead of duplicating:
sh
gh pr view --json url,state 2>/dev/null
  • If the command returns a PR with
    state
    equal to
    OPEN
    : update it with
    gh pr edit --title "…" --body-file <file>
    rather than opening a second.
  • If no PR exists, or the returned PR is merged/closed: write the body to a temp file and create a new one. Passing multi-line markdown with checkboxes through
    --body
    is flaky;
    --body-file
    is reliable.
sh
gh pr create --base <base> --title "…" --body-file <bodyfile>
首先检查当前分支是否已有PR,避免重复创建:
sh
gh pr view --json url,state 2>/dev/null
  • 如果命令返回状态为
    OPEN
    的PR
    :使用
    gh pr edit --title "…" --body-file <file>
    更新该PR,而非创建新PR。
  • 如果不存在PR,或返回的PR已合并/关闭:将正文写入临时文件并创建新PR。通过
    --body
    传递带复选框的多行Markdown内容不可靠;
    --body-file
    更稳定。
sh
gh pr create --base <base> --title "…" --body-file <bodyfile>

add --draft when the user wants a draft, or the work is incomplete

如果用户需要草稿PR,或工作未完成,添加--draft参数


Use a path in the system temp dir for the body file and remove it afterward.

使用系统临时目录存储正文文件,完成后删除该文件。

8. Advance the linked issue

8. 更新关联问题状态

Opening the PR is the moment the linked issue moves from being worked to awaiting review, so flip its lifecycle label
in-progress
in-review
(the same transition issuekit's
sync
mode performs when a PR opens). Do this only when the PR references an issue, meaning the
#123
/
Closes #123
found in Gather context; skip this step entirely if there is none.
  • Prefer issuekit when it's installed. Invoke it to reconcile the label so the tracker logic lives in one place. Otherwise fall back to the equivalent
    gh
    call yourself:
sh
gh issue edit <n> --remove-label in-progress --add-label in-review
  • Run it without asking. This is prkit's one exemption from the preview rule, and it belongs to this step rather than to whoever called it. Opening the pull request is the instruction to move the issue to review, so a confirmation asks a question the invocation already answered, and it costs the one thing this step protects: an issue that still advertises itself as being worked while its PR sits open for review. Report the flip in the hand-off rather than proposing it first.
  • The exemption covers two starting states and no others. An issue carrying
    in-progress
    gets the flip above. An issue carrying
    ready
    gets
    in-review
    added, with no removal, and you say what you found. That is the state issuekit
    start
    produces, so it is the other one a PR can legitimately arrive from.
  • Any other lifecycle state is drift, not a transition. For
    blocked
    ,
    needs-planning
    ,
    triage
    ,
    needs-info
    , already
    in-review
    , or no lifecycle label at all, stop and change nothing. Report the state you found. Ask when a human is present; escalate when the run is unattended. A label nobody checked is worse than a label nobody set.
  • Everything else in prkit still previews. The exemption is this one label move. Creating the PR, committing a handed-in path, and force-pushing a sync are unchanged.
  • If the
    in-review
    label is missing from the repo, point the user at repokit or give
    gh label create in-review --color 5319E7 --description "a PR is open, awaiting review or merge"
    , and don't mutate around the gap. The exemption skips the prompt, never the provisioning check.
打开PR意味着关联问题从「进行中」状态变为「待审核」状态,因此需将其生命周期标签从
in-progress
改为
in-review
(与issuekit的
sync
模式在PR打开时执行的转换操作相同)。仅当PR引用了问题时执行本步骤(即收集上下文中找到的
#123
/
Closes #123
);若无关联问题,则完全跳过本步骤。
  • 优先使用已安装的issuekit。调用issuekit更新标签,确保跟踪逻辑集中在一处。否则,使用等效的
    gh
    命令:
sh
gh issue edit <n> --remove-label in-progress --add-label in-review
  • 无需询问即可执行。这是prkit唯一豁免预览规则的步骤,且属于本步骤的固有操作,而非调用者的指令。打开拉取请求本身就是将问题移至审核状态的指令,因此确认操作相当于重复提问,且会破坏本步骤要避免的问题:PR已待审核,但问题仍显示为「进行中」。执行后告知用户标签已更新,而非事先询问。
  • 豁免仅覆盖两种起始状态。带有
    in-progress
    标签的问题执行上述标签切换操作。带有
    ready
    标签的问题添加
    in-review
    标签,不删除原有标签,并告知用户当前状态。
    ready
    是issuekit的
    start
    命令生成的状态,因此是PR可能对应的另一种合法起始状态。
  • 任何其他生命周期状态均为异常,而非正常转换。对于
    blocked
    needs-planning
    triage
    needs-info
    、已处于
    in-review
    或无生命周期标签的问题,请停止操作并保持标签不变。告知用户当前状态。如果有用户在场,请询问用户;如果是无人值守的运行,则上报异常。错误的标签比未设置标签更糟糕。
  • prkit的其他所有操作仍需预览。豁免仅适用于本次标签更新操作。创建PR、提交用户指定路径、强制推送同步分支等操作均保持原有规则。
  • 如果仓库中不存在
    in-review
    标签,请引导用户使用repokit或执行
    gh label create in-review --color 5319E7 --description "a PR is open, awaiting review or merge"
    ,不要跳过标签检查。豁免仅跳过提示,不跳过标签存在性检查。

9. Hand off

9. 操作收尾

Write this section in the procedural register: one instruction per sentence, active voice, present tense, no metaphor.
What changed. Report the PR created or updated (title and number), whether a sync rebase ran, whether a handed-in path was committed, whether a proof section was embedded, and whether the linked issue was flipped to
in-review
.
Where it landed. Give the PR URL and the branch it points at. Mention that CI will run if configured.
Next. The PR now waits on review, so the move is on the reviewer's side: mergekit
start <n>
when it's installed pulls it down into a worktree for local review and QA; otherwise review it on GitHub. First offer, don't auto-run, the small follow-ups when they apply:
gh pr edit --add-reviewer <user>
,
--add-label <label>
, or
gh pr ready
for a draft. prkit's job ends here.
本部分采用流程化表述:每句一个指令,主动语态,现在时态,无比喻。
更改内容:报告PR已创建或更新(标题和编号)、是否执行了同步变基、是否提交了用户指定路径、是否嵌入了验证章节、是否将关联问题切换至
in-review
状态。
结果位置:提供PR的URL及其指向的分支。提及如果配置了CI,CI将自动运行。
下一步操作:PR现在等待审核,后续操作由审核者负责:如果已安装mergekit,执行
start <n>
可将PR拉取到工作树进行本地审核和QA;否则在GitHub上直接审核。当适用时,主动提供小型后续操作选项(而非自动执行):
gh pr edit --add-reviewer <user>
--add-label <label>
,或针对草稿PR执行
gh pr ready
。prkit的任务至此结束。

Notes

注意事项

  • Never merge, close, or force-push without an explicit ask. Creating or editing a PR is fine;
    gh pr merge
    is not, unless requested.
  • Uncommitted changes are not in a PR. If
    git status
    shows staged or unstaged work the user seems to want included, point it out and offer to commit first, rather than silently leaving it behind or committing it without asking.
  • If the branch is not ahead of the base (no commits), stop and say there's nothing to open a PR for.
  • Proof embedding is optional and self-contained. prkit only reads verifykit's
    proof.md
    and embeds it; it never runs the publish itself (that's verifykit's job, with its own bundled script). No verifykit bundle → no Proof section, and prkit works exactly as it always has.
  • Advancing the linked issue is optional and exempt from the preview rule. The flip only happens when the PR references an issue, and prefers issuekit when installed, falling back to a plain
    gh issue edit
    . It runs unprompted from
    in-progress
    or
    ready
    and refuses every other state, because those two are the only ones a PR legitimately arrives from. The exemption is the step's, not the caller's: a human at the keyboard and an unattended orchestrator get exactly the same behavior, and prkit never widens it. No linked issue → prkit opens the PR exactly as before.
  • No shell or
    gh
    available (e.g. a browser-based agent)? Then you can't push or call
    gh
    . Instead read the diff the user provides and print the finished PR title and body as codeblocks for them to paste into the GitHub "New pull request" form.
  • 切勿在未明确请求的情况下执行合并、关闭或强制推送操作。创建或编辑PR是允许的;除非用户明确要求,否则不要执行
    gh pr merge
  • 未提交的更改不会包含在PR中。如果
    git status
    显示存在用户可能希望包含的暂存或未暂存更改,请告知用户并主动提出协助提交,而非静默遗漏或未经询问直接提交。
  • 如果分支未领先于基准分支(无提交),请停止操作并告知用户没有可用于创建PR的内容。
  • 验证工件嵌入是可选且独立的。prkit仅读取verifykit的
    proof.md
    并嵌入;从不自行执行发布操作(这是verifykit的任务,由其自带脚本完成)。无verifykit验证包则无验证章节,prkit的其他操作保持不变。
  • 更新关联问题状态是可选且豁免预览规则的。仅当PR引用了问题时才执行状态切换,优先使用已安装的issuekit,否则使用普通的
    gh issue edit
    命令。从
    in-progress
    ready
    状态切换时无需提示,其他状态则拒绝执行,因为这两种状态是PR对应的唯一合法起始状态。豁免适用于本步骤,而非调用者:无论用户是否在场,无人值守的编排器均执行相同操作,prkit绝不会扩大豁免范围。无关联问题则prkit按原有流程打开PR。
  • 如果无法使用shell或
    gh
    (例如基于浏览器的Agent),则无法推送分支或调用
    gh
    。此时请读取用户提供的差异内容,将生成的PR标题正文以代码块形式打印出来,供用户粘贴到GitHub的「新建拉取请求」表单中。