prepare-pr

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Prepare PR

准备PR

Overview

概述

Prepare a PR head branch for merge with review fixes, green gates, and deterministic merge handoff artifacts.
为PR头分支完成合并准备工作,包括修复评审问题、通过所有检查环节,以及生成用于确定性合并交接的工件。

Inputs

输入

  • Ask for PR number or URL.
  • If missing, use
    .local/pr-meta.env
    from the PR worktree if present.
  • If ambiguous, ask.
  • 请求提供PR编号或URL。
  • 如果未提供,若PR工作树中存在
    .local/pr-meta.env
    则使用该文件。
  • 若存在歧义,发起询问。

Safety

安全规则

  • Never push to
    main
    or
    origin/main
    . Push only to the PR head branch.
  • Never run
    git push
    without explicit remote and branch. Do not run bare
    git push
    .
  • Do not run gateway stop commands. Do not kill processes. Do not touch port 18792.
  • Do not run
    git clean -fdx
    .
  • Do not run
    git add -A
    or
    git add .
    .
  • 切勿推送到
    main
    origin/main
    分支。仅可推送到PR头分支。
  • 切勿在未指定明确远程仓库和分支的情况下执行
    git push
    。不要执行无参数的
    git push
  • 不要执行网关停止命令。不要终止进程。不要触碰端口18792。
  • 不要执行
    git clean -fdx
  • 不要执行
    git add -A
    git add .

Execution Rule

执行规则

  • Execute the workflow. Do not stop after printing the TODO checklist.
  • If delegating, require the delegate to run commands and capture outputs.
  • 执行完整工作流。不要在打印待办事项清单后停止。
  • 如果委托他人执行,要求被委托者运行命令并捕获输出结果。

Completion Criteria

完成标准

  • Rebase PR commits onto
    origin/main
    .
  • Fix all BLOCKER and IMPORTANT items from
    .local/review.md
    .
  • Commit prep changes with required subject format.
  • Run required gates and pass (
    pnpm test
    may be skipped only for high-confidence docs-only changes).
  • Push the updated HEAD back to the PR head branch.
  • Write
    .local/prep.md
    and
    .local/prep.env
    .
  • Output exactly:
    PR is ready for /mergepr
    .
  • 将PR提交基于
    origin/main
    分支进行变基。
  • 修复
    .local/review.md
    中所有BLOCKER和IMPORTANT级别的问题。
  • 按照要求的主题格式提交准备阶段的修改。
  • 运行必要的检查环节并通过(仅当高度确认是纯文档修改时,可跳过
    pnpm test
    )。
  • 将更新后的HEAD推回PR头分支。
  • 生成
    .local/prep.md
    .local/prep.env
    文件。
  • 输出内容必须为:
    PR is ready for /mergepr

First: Create a TODO Checklist

第一步:创建待办事项清单

Create a checklist of all prep steps, print it, then continue and execute the commands.
创建包含所有准备步骤的清单,打印后继续执行命令。

Setup: Use a Worktree

环境设置:使用工作树

Use an isolated worktree for all prep work.
sh
repo_root=$(git rev-parse --show-toplevel)
cd "$repo_root"
gh auth status

WORKTREE_DIR=".worktrees/pr-<PR>"
if [ ! -d "$WORKTREE_DIR" ]; then
  git fetch origin main
  git worktree add "$WORKTREE_DIR" -b temp/pr-<PR> origin/main
fi
cd "$WORKTREE_DIR"
mkdir -p .local
Run all commands inside the worktree directory.
使用独立的工作树完成所有准备工作。
sh
repo_root=$(git rev-parse --show-toplevel)
cd "$repo_root"
gh auth status

WORKTREE_DIR=".worktrees/pr-<PR>"
if [ ! -d "$WORKTREE_DIR" ]; then
  git fetch origin main
  git worktree add "$WORKTREE_DIR" -b temp/pr-<PR> origin/main
fi
cd "$WORKTREE_DIR"
mkdir -p .local
所有命令均在工作树目录内执行。

Load Review Artifacts (Mandatory)

加载评审工件(必填)

sh
if [ ! -f .local/review.md ]; then
  echo "Missing .local/review.md. Run /review-pr first and save findings."
  exit 1
fi

if [ ! -f .local/pr-meta.env ]; then
  echo "Missing .local/pr-meta.env. Run /review-pr first and save metadata."
  exit 1
fi

sed -n '1,220p' .local/review.md
source .local/pr-meta.env
sh
if [ ! -f .local/review.md ]; then
  echo "Missing .local/review.md. Run /review-pr first and save findings."
  exit 1
fi

if [ ! -f .local/pr-meta.env ]; then
  echo "Missing .local/pr-meta.env. Run /review-pr first and save metadata."
  exit 1
fi

sed -n '1,220p' .local/review.md
source .local/pr-meta.env

Steps

步骤

  1. Identify PR meta with one API call
sh
pr_meta_json=$(gh pr view <PR> --json number,title,author,headRefName,headRefOid,baseRefName,headRepository,headRepositoryOwner,body)
printf '%s\n' "$pr_meta_json" | jq '{number,title,author:.author.login,head:.headRefName,headSha:.headRefOid,base:.baseRefName,headRepo:.headRepository.nameWithOwner,headRepoOwner:.headRepositoryOwner.login,headRepoName:.headRepository.name,body}'

pr_number=$(printf '%s\n' "$pr_meta_json" | jq -r .number)
contrib=$(printf '%s\n' "$pr_meta_json" | jq -r .author.login)
head=$(printf '%s\n' "$pr_meta_json" | jq -r .headRefName)
pr_head_sha_before=$(printf '%s\n' "$pr_meta_json" | jq -r .headRefOid)
head_owner=$(printf '%s\n' "$pr_meta_json" | jq -r '.headRepositoryOwner.login // empty')
head_repo_name=$(printf '%s\n' "$pr_meta_json" | jq -r '.headRepository.name // empty')
head_repo_url=$(printf '%s\n' "$pr_meta_json" | jq -r '.headRepository.url // empty')

if [ -n "${PR_HEAD:-}" ] && [ "$head" != "$PR_HEAD" ]; then
  echo "ERROR: PR head branch changed from $PR_HEAD to $head. Re-run /review-pr."
  exit 1
fi
  1. Fetch PR head and rebase on latest
    origin/main
sh
git fetch origin pull/<PR>/head:pr-<PR> --force
git checkout -B pr-<PR>-prep pr-<PR>
git fetch origin main
git rebase origin/main
If conflicts happen:
  • Resolve each conflicted file.
  • Run
    git add <resolved_file>
    for each file.
  • Run
    git rebase --continue
    .
If the rebase gets confusing or you resolve conflicts 3 or more times, stop and report.
  1. Fix issues from
    .local/review.md
  • Fix all BLOCKER and IMPORTANT items.
  • NITs are optional.
  • Keep scope tight.
Keep a running log in
.local/prep.md
:
  • List which review items you fixed.
  • List which files you touched.
  • Note behavior changes.
  1. Optional quick feedback tests before full gates
Targeted tests are optional quick feedback, not a substitute for full gates.
If running targeted tests in a fresh worktree:
sh
if [ ! -x node_modules/.bin/vitest ]; then
  pnpm install --frozen-lockfile
fi
  1. Commit prep fixes with required subject format
Use
scripts/committer
with explicit file paths.
Required subject format:
  • fix: <summary> (openclaw#<PR>) thanks @<author>
sh
commit_msg="fix: <summary> (openclaw#$pr_number) thanks @$contrib"
scripts/committer "$commit_msg" <changed file 1> <changed file 2> ...
If there are no local changes, do not create a no-op commit.
Post-commit validation (mandatory):
sh
subject=$(git log -1 --pretty=%s)
echo "$subject" | rg -q "openclaw#$pr_number" || { echo "ERROR: commit subject missing openclaw#$pr_number"; exit 1; }
echo "$subject" | rg -q "thanks @$contrib" || { echo "ERROR: commit subject missing thanks @$contrib"; exit 1; }
  1. Decide verification mode and run required gates before pushing
If you are highly confident the change is docs-only, you may skip
pnpm test
.
High-confidence docs-only criteria (all must be true):
  • Every changed file is documentation-only (
    docs/**
    ,
    README*.md
    ,
    CHANGELOG.md
    ,
    *.md
    ,
    *.mdx
    ,
    mintlify.json
    ,
    docs.json
    ).
  • No code, runtime, test, dependency, or build config files changed (
    src/**
    ,
    extensions/**
    ,
    apps/**
    ,
    package.json
    , lockfiles, TS/JS config, test files, scripts).
  • .local/review.md
    does not call for non-doc behavior fixes.
Suggested check:
sh
changed_files=$(git diff --name-only origin/main...HEAD)
non_docs=$(printf "%s\n" "$changed_files" | grep -Ev '^(docs/|README.*\.md$|CHANGELOG\.md$|.*\.md$|.*\.mdx$|mintlify\.json$|docs\.json$)' || true)

docs_only=false
if [ -n "$changed_files" ] && [ -z "$non_docs" ]; then
  docs_only=true
fi

echo "docs_only=$docs_only"
Bootstrap dependencies in a fresh worktree before gates:
sh
if [ ! -d node_modules ]; then
  pnpm install --frozen-lockfile
fi
Run required gates:
sh
pnpm build
pnpm check

if [ "$docs_only" = "true" ]; then
  echo "Docs-only change detected with high confidence; skipping pnpm test." | tee -a .local/prep.md
else
  pnpm test
fi
Require all required gates to pass. If something fails, fix, commit, and rerun. Allow at most 3 fix-and-rerun cycles.
  1. Push safely to the PR head branch
Build
prhead
from owner/name first, then validate remote branch SHA before push.
sh
if [ -n "$head_owner" ] && [ -n "$head_repo_name" ]; then
  head_repo_push_url="https://github.com/$head_owner/$head_repo_name.git"
elif [ -n "$head_repo_url" ] && [ "$head_repo_url" != "null" ]; then
  case "$head_repo_url" in
    *.git) head_repo_push_url="$head_repo_url" ;;
    *) head_repo_push_url="$head_repo_url.git" ;;
  esac
else
  echo "ERROR: unable to determine PR head repo push URL"
  exit 1
fi

git remote add prhead "$head_repo_push_url" 2>/dev/null || git remote set-url prhead "$head_repo_push_url"

echo "Pushing to branch: $head"
if [ "$head" = "main" ] || [ "$head" = "master" ]; then
  echo "ERROR: head branch is main/master. This is wrong. Stopping."
  exit 1
fi

remote_sha=$(git ls-remote prhead "refs/heads/$head" | awk '{print $1}')
if [ -z "$remote_sha" ]; then
  echo "ERROR: remote branch refs/heads/$head not found on prhead"
  exit 1
fi
if [ "$remote_sha" != "$pr_head_sha_before" ]; then
  echo "ERROR: expected remote SHA $pr_head_sha_before, got $remote_sha. Re-fetch metadata and rebase first."
  exit 1
fi

git push --force-with-lease=refs/heads/$head:$pr_head_sha_before prhead HEAD:$head || push_failed=1
If lease push fails because head moved, perform one automatic retry:
sh
if [ "${push_failed:-0}" = "1" ]; then
  echo "Lease push failed, retrying once with fresh PR head..."

  pr_head_sha_before=$(gh pr view <PR> --json headRefOid --jq .headRefOid)
  git fetch origin pull/<PR>/head:pr-<PR>-latest --force
  git rebase pr-<PR>-latest

  pnpm build
  pnpm check
  if [ "$docs_only" != "true" ]; then
    pnpm test
  fi

  git push --force-with-lease=refs/heads/$head:$pr_head_sha_before prhead HEAD:$head
fi
  1. Verify PR head and base relation (Mandatory)
sh
prep_head_sha=$(git rev-parse HEAD)
pr_head_sha_after=$(gh pr view <PR> --json headRefOid --jq .headRefOid)

if [ "$prep_head_sha" != "$pr_head_sha_after" ]; then
  echo "ERROR: pushed head SHA does not match PR head SHA."
  exit 1
fi

git fetch origin main
git fetch origin pull/<PR>/head:pr-<PR>-verify --force
git merge-base --is-ancestor origin/main pr-<PR>-verify && echo "PR is up to date with main" || (echo "ERROR: PR is still behind main, rebase again" && exit 1)
git branch -D pr-<PR>-verify 2>/dev/null || true
  1. Write prep summary artifacts (Mandatory)
Write
.local/prep.md
and
.local/prep.env
for merge handoff.
sh
contrib_id=$(gh api users/$contrib --jq .id)
coauthor_email="${contrib_id}+${contrib}@users.noreply.github.com"

cat > .local/prep.env <<EOF_ENV
PR_NUMBER=$pr_number
PR_AUTHOR=$contrib
PR_HEAD=$head
PR_HEAD_SHA_BEFORE=$pr_head_sha_before
PREP_HEAD_SHA=$prep_head_sha
COAUTHOR_EMAIL=$coauthor_email
EOF_ENV

ls -la .local/prep.md .local/prep.env
wc -l .local/prep.md .local/prep.env
  1. Output
Include a diff stat summary:
sh
git diff --stat origin/main..HEAD
git diff --shortstat origin/main..HEAD
Report totals: X files changed, Y insertions(+), Z deletions(-).
If gates passed and push succeeded, print exactly:
PR is ready for /mergepr
Otherwise, list remaining failures and stop.
  1. 通过一次API调用获取PR元数据
sh
pr_meta_json=$(gh pr view <PR> --json number,title,author,headRefName,headRefOid,baseRefName,headRepository,headRepositoryOwner,body)
printf '%s\n' "$pr_meta_json" | jq '{number,title,author:.author.login,head:.headRefName,headSha:.headRefOid,base:.baseRefName,headRepo:.headRepository.nameWithOwner,headRepoOwner:.headRepositoryOwner.login,headRepoName:.headRepository.name,body}'

pr_number=$(printf '%s\n' "$pr_meta_json" | jq -r .number)
contrib=$(printf '%s\n' "$pr_meta_json" | jq -r .author.login)
head=$(printf '%s\n' "$pr_meta_json" | jq -r .headRefName)
pr_head_sha_before=$(printf '%s\n' "$pr_meta_json" | jq -r .headRefOid)
head_owner=$(printf '%s\n' "$pr_meta_json" | jq -r '.headRepositoryOwner.login // empty')
head_repo_name=$(printf '%s\n' "$pr_meta_json" | jq -r '.headRepository.name // empty')
head_repo_url=$(printf '%s\n' "$pr_meta_json" | jq -r '.headRepository.url // empty')

if [ -n "${PR_HEAD:-}" ] && [ "$head" != "$PR_HEAD" ]; then
  echo "ERROR: PR head branch changed from $PR_HEAD to $head. Re-run /review-pr."
  exit 1
fi
  1. 获取PR头分支并基于最新
    origin/main
    变基
sh
git fetch origin pull/<PR>/head:pr-<PR> --force
git checkout -B pr-<PR>-prep pr-<PR>
git fetch origin main
git rebase origin/main
如果发生冲突:
  • 解决每个冲突文件的冲突。
  • 为每个已解决的文件执行
    git add <resolved_file>
  • 执行
    git rebase --continue
如果变基过程混乱或解决冲突次数达到3次及以上,停止操作并上报。
  1. 修复
    .local/review.md
    中的问题
  • 修复所有BLOCKER和IMPORTANT级别的问题。
  • NIT级别的问题为可选修复项。
  • 严格控制修改范围。
.local/prep.md
中持续记录:
  • 列出已修复的评审问题。
  • 列出已修改的文件。
  • 记录行为变更。
  1. 完整检查前的可选快速反馈测试
针对性测试是可选的快速反馈方式,不能替代完整检查环节。
如果在新的工作树中运行针对性测试:
sh
if [ ! -x node_modules/.bin/vitest ]; then
  pnpm install --frozen-lockfile
fi
  1. 按照要求的主题格式提交准备阶段的修复
使用
scripts/committer
并指定明确的文件路径。
必填主题格式:
  • fix: <summary> (openclaw#<PR>) thanks @<author>
sh
commit_msg="fix: <summary> (openclaw#$pr_number) thanks @$contrib"
scripts/committer "$commit_msg" <changed file 1> <changed file 2> ...
如果没有本地修改,不要创建无操作的提交。
提交后验证(必填):
sh
subject=$(git log -1 --pretty=%s)
echo "$subject" | rg -q "openclaw#$pr_number" || { echo "ERROR: commit subject missing openclaw#$pr_number"; exit 1; }
echo "$subject" | rg -q "thanks @$contrib" || { echo "ERROR: commit subject missing thanks @$contrib"; exit 1; }
  1. 决定验证模式并在推送前运行必要的检查环节
如果高度确认修改仅涉及文档,可跳过
pnpm test
高度确认纯文档修改的标准(需全部满足):
  • 所有修改的文件均为纯文档文件(
    docs/**
    ,
    README*.md
    ,
    CHANGELOG.md
    ,
    *.md
    ,
    *.mdx
    ,
    mintlify.json
    ,
    docs.json
    )。
  • 未修改代码、运行时、测试、依赖或构建配置文件(
    src/**
    ,
    extensions/**
    ,
    apps/**
    ,
    package.json
    , 锁文件, TS/JS配置, 测试文件, 脚本)。
  • .local/review.md
    未要求修复非文档类行为问题。
建议执行的检查:
sh
changed_files=$(git diff --name-only origin/main...HEAD)
non_docs=$(printf "%s\n" "$changed_files" | grep -Ev '^(docs/|README.*\.md$|CHANGELOG\.md$|.*\.md$|.*\.mdx$|mintlify\.json$|docs\.json$)' || true)

docs_only=false
if [ -n "$changed_files" ] && [ -z "$non_docs" ]; then
  docs_only=true
fi

echo "docs_only=$docs_only"
在新的工作树中运行检查前先安装依赖:
sh
if [ ! -d node_modules ]; then
  pnpm install --frozen-lockfile
fi
运行必要的检查环节:
sh
pnpm build
pnpm check

if [ "$docs_only" = "true" ]; then
  echo "Docs-only change detected with high confidence; skipping pnpm test." | tee -a .local/prep.md
else
  pnpm test
fi
要求所有必要的检查环节均通过。如果有检查失败,修复问题、提交并重新运行。最多允许3次修复并重试的循环。
  1. 安全推送到PR头分支
先从仓库所有者/名称构建
prhead
,然后在推送前验证远程分支的SHA值。
sh
if [ -n "$head_owner" ] && [ -n "$head_repo_name" ]; then
  head_repo_push_url="https://github.com/$head_owner/$head_repo_name.git"
elif [ -n "$head_repo_url" ] && [ "$head_repo_url" != "null" ]; then
  case "$head_repo_url" in
    *.git) head_repo_push_url="$head_repo_url" ;;
    *) head_repo_push_url="$head_repo_url.git" ;;
  esac
else
  echo "ERROR: unable to determine PR head repo push URL"
  exit 1
fi

git remote add prhead "$head_repo_push_url" 2>/dev/null || git remote set-url prhead "$head_repo_push_url"

echo "Pushing to branch: $head"
if [ "$head" = "main" ] || [ "$head" = "master" ]; then
  echo "ERROR: head branch is main/master. This is wrong. Stopping."
  exit 1
fi

remote_sha=$(git ls-remote prhead "refs/heads/$head" | awk '{print $1}')
if [ -z "$remote_sha" ]; then
  echo "ERROR: remote branch refs/heads/$head not found on prhead"
  exit 1
fi
if [ "$remote_sha" != "$pr_head_sha_before" ]; then
  echo "ERROR: expected remote SHA $pr_head_sha_before, got $remote_sha. Re-fetch metadata and rebase first."
  exit 1
fi

git push --force-with-lease=refs/heads/$head:$pr_head_sha_before prhead HEAD:$head || push_failed=1
如果因为头分支已更新导致租约推送失败,自动重试一次:
sh
if [ "${push_failed:-0}" = "1" ]; then
  echo "Lease push failed, retrying once with fresh PR head..."

  pr_head_sha_before=$(gh pr view <PR> --json headRefOid --jq .headRefOid)
  git fetch origin pull/<PR>/head:pr-<PR>-latest --force
  git rebase pr-<PR>-latest

  pnpm build
  pnpm check
  if [ "$docs_only" != "true" ]; then
    pnpm test
  fi

  git push --force-with-lease=refs/heads/$head:$pr_head_sha_before prhead HEAD:$head
fi
  1. 验证PR头分支与基准分支的关系(必填)
sh
prep_head_sha=$(git rev-parse HEAD)
pr_head_sha_after=$(gh pr view <PR> --json headRefOid --jq .headRefOid)

if [ "$prep_head_sha" != "$pr_head_sha_after" ]; then
  echo "ERROR: pushed head SHA does not match PR head SHA."
  exit 1
fi

git fetch origin main
git fetch origin pull/<PR>/head:pr-<PR>-verify --force
git merge-base --is-ancestor origin/main pr-<PR>-verify && echo "PR is up to date with main" || (echo "ERROR: PR is still behind main, rebase again" && exit 1)
git branch -D pr-<PR>-verify 2>/dev/null || true
  1. 编写准备阶段总结工件(必填)
编写
.local/prep.md
.local/prep.env
用于合并交接。
sh
contrib_id=$(gh api users/$contrib --jq .id)
coauthor_email="${contrib_id}+${contrib}@users.noreply.github.com"

cat > .local/prep.env <<EOF_ENV
PR_NUMBER=$pr_number
PR_AUTHOR=$contrib
PR_HEAD=$head
PR_HEAD_SHA_BEFORE=$pr_head_sha_before
PREP_HEAD_SHA=$prep_head_sha
COAUTHOR_EMAIL=$coauthor_email
EOF_ENV

ls -la .local/prep.md .local/prep.env
wc -l .local/prep.md .local/prep.env
  1. 输出
包含差异统计摘要:
sh
git diff --stat origin/main..HEAD
git diff --shortstat origin/main..HEAD
报告统计结果:X个文件被修改,Y处插入(+),Z处删除(-)。
如果所有检查环节通过且推送成功,输出内容必须为:
PR is ready for /mergepr
否则,列出剩余失败项并停止操作。

Guardrails

防护规则

  • Worktree only.
  • Do not delete the worktree on success.
    /mergepr
    may reuse it.
  • Do not run
    gh pr merge
    .
  • Never push to main. Only push to the PR head branch.
  • Run and pass all required gates before pushing.
    pnpm test
    may be skipped only for high-confidence docs-only changes, and the skip must be explicitly recorded in
    .local/prep.md
    .
  • 仅使用工作树。
  • 成功后不要删除工作树。
    /mergepr
    可能会复用该工作树。
  • 不要执行
    gh pr merge
  • 切勿推送到main分支。仅可推送到PR头分支。
  • 推送前必须运行并通过所有必要的检查环节。仅当高度确认是纯文档修改时可跳过
    pnpm test
    ,且跳过操作必须在
    .local/prep.md
    中明确记录。