github-pr-workflow
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGitHub Pull Request Workflow
GitHub Pull Request 工作流程
Complete guide for managing the PR lifecycle. Each section shows the way first, then the + fallback for machines without .
ghgitcurlgh管理PR生命周期的完整指南。每个部分先展示使用的方法,然后提供针对没有的机器的 + 替代方案。
ghghgitcurlPrerequisites
前提条件
- Authenticated with GitHub (see skill)
github-auth - Inside a git repository with a GitHub remote
- 已通过GitHub认证(参考技能)
github-auth - 处于带有GitHub远程仓库的git本地仓库中
Quick Auth Detection
快速认证检测
bash
undefinedbash
undefinedDetermine which method to use throughout this workflow
确定此工作流全程使用的方法
if command -v gh &>/dev/null && gh auth status &>/dev/null; then
AUTH="gh"
else
AUTH="git"
Ensure we have a token for API calls
if [ -z "$GITHUB_TOKEN" ]; then
if [ -f ~/.hermes/.env ] && grep -q "^GITHUB_TOKEN=" ~/.hermes/.env; then
GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d '\n\r')
elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then
GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]:([^@])@.*|\1|')
fi
fi
fi
echo "Using: $AUTH"
undefinedif command -v gh &>/dev/null && gh auth status &>/dev/null; then
AUTH="gh"
else
AUTH="git"
确保我们有用于API调用的令牌
if [ -z "$GITHUB_TOKEN" ]; then
if [ -f ~/.hermes/.env ] && grep -q "^GITHUB_TOKEN=" ~/.hermes/.env; then
GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d '\n\r')
elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then
GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]:([^@])@.*|\1|')
fi
fi
fi
echo "Using: $AUTH"
undefinedExtracting Owner/Repo from the Git Remote
从Git远程仓库提取所有者/仓库名
Many commands need . Extract it from the git remote:
curlowner/repobash
undefined许多命令需要信息。从git远程仓库中提取:
curlowner/repobash
undefinedWorks for both HTTPS and SSH remote URLs
适用于HTTPS和SSH两种远程仓库URL
REMOTE_URL=$(git remote get-url origin)
OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github.com[:/]||; s|.git$||')
OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1)
REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)
echo "Owner: $OWNER, Repo: $REPO"
---REMOTE_URL=$(git remote get-url origin)
OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github.com[:/]||; s|.git$||')
OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1)
REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)
echo "Owner: $OWNER, Repo: $REPO"
---1. Branch Creation
1. 分支创建
This part is pure — identical either way:
gitbash
undefined这部分完全使用——两种方式操作一致:
gitbash
undefinedMake sure you're up to date
确保本地代码是最新的
git fetch origin
git checkout main && git pull origin main
git fetch origin
git checkout main && git pull origin main
Create and switch to a new branch
创建并切换到新分支
git checkout -b feat/add-user-authentication
Branch naming conventions:
- `feat/description` — new features
- `fix/description` — bug fixes
- `refactor/description` — code restructuring
- `docs/description` — documentation
- `ci/description` — CI/CD changesgit checkout -b feat/add-user-authentication
分支命名规范:
- `feat/description` —— 新功能
- `fix/description` —— Bug修复
- `refactor/description` —— 代码重构
- `docs/description` —— 文档更新
- `ci/description` —— CI/CD变更2. Making Commits
2. 提交代码
Use the agent's file tools (, ) to make changes, then commit:
write_filepatchbash
undefined使用代理的文件工具(、)修改代码,然后提交:
write_filepatchbash
undefinedStage specific files
暂存指定文件
git add src/auth.py src/models/user.py tests/test_auth.py
git add src/auth.py src/models/user.py tests/test_auth.py
Commit with a conventional commit message
使用规范提交信息提交
git commit -m "feat: add JWT-based user authentication
- Add login/register endpoints
- Add User model with password hashing
- Add auth middleware for protected routes
- Add unit tests for auth flow"
Commit message format (Conventional Commits):type(scope): short description
Longer explanation if needed. Wrap at 72 characters.
Types: `feat`, `fix`, `refactor`, `docs`, `test`, `ci`, `chore`, `perf`git commit -m "feat: add JWT-based user authentication
- Add login/register endpoints
- Add User model with password hashing
- Add auth middleware for protected routes
- Add unit tests for auth flow"
提交信息格式(Conventional Commits):type(scope): 简短描述
如需详细说明可在此处补充,每行不超过72个字符。
类型:`feat`、`fix`、`refactor`、`docs`、`test`、`ci`、`chore`、`perf`3. Pushing and Creating a PR
3. 推送分支并创建PR
Push the Branch (same either way)
推送分支(两种方式操作一致)
bash
git push -u origin HEADbash
git push -u origin HEADCreate the PR
创建PR
With gh:
bash
gh pr create \
--title "feat: add JWT-based user authentication" \
--body "## Summary
- Adds login and register API endpoints
- JWT token generation and validation使用gh:
bash
gh pr create \
--title "feat: add JWT-based user authentication" \
--body "## Summary
- Adds login and register API endpoints
- JWT token generation and validationTest Plan
Test Plan
- Unit tests pass
Closes #42"
Options: `--draft`, `--reviewer user1,user2`, `--label "enhancement"`, `--base develop`
**With git + curl:**
```bash
BRANCH=$(git branch --show-current)
curl -s -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/$OWNER/$REPO/pulls \
-d "{
\"title\": \"feat: add JWT-based user authentication\",
\"body\": \"## Summary\nAdds login and register API endpoints.\n\nCloses #42\",
\"head\": \"$BRANCH\",
\"base\": \"main\"
}"The response JSON includes the PR — save it for later commands.
numberTo create as a draft, add to the JSON body.
"draft": true- Unit tests pass
Closes #42"
可选参数:`--draft`(创建草稿PR)、`--reviewer user1,user2`(指定审核人)、`--label "enhancement"`(添加标签)、`--base develop`(指定目标分支)
**使用git + curl:**
```bash
BRANCH=$(git branch --show-current)
curl -s -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/$OWNER/$REPO/pulls \
-d "{
\"title\": \"feat: add JWT-based user authentication\",
\"body\": \"## Summary\nAdds login and register API endpoints.\n\nCloses #42\",
\"head\": \"$BRANCH\",
\"base\": \"main\"
}"返回的JSON中包含PR的——请保存该值用于后续命令。
number如需创建草稿PR,在JSON体中添加。
"draft": true4. Monitoring CI Status
4. 监控CI状态
Check CI Status
检查CI状态
With gh:
bash
undefined使用gh:
bash
undefinedOne-shot check
单次检查
gh pr checks
gh pr checks
Watch until all checks finish (polls every 10s)
持续监控直到所有检查完成(每10秒轮询一次)
gh pr checks --watch
**With git + curl:**
```bashgh pr checks --watch
**使用git + curl:**
```bashGet the latest commit SHA on the current branch
获取当前分支最新提交的SHA值
SHA=$(git rev-parse HEAD)
SHA=$(git rev-parse HEAD)
Query the combined status
查询综合状态
curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c " import sys, json data = json.load(sys.stdin) print(f"Overall: {data['state']}") for s in data.get('statuses', []): print(f" {s['context']}: {s['state']} - {s.get('description', '')}")"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c " import sys, json data = json.load(sys.stdin) print(f"Overall: {data['state']}") for s in data.get('statuses', []): print(f" {s['context']}: {s['state']} - {s.get('description', '')}")"
curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c " import sys, json data = json.load(sys.stdin) print(f"Overall: {data['state']}") for s in data.get('statuses', []): print(f" {s['context']}: {s['state']} - {s.get('description', '')}")"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c " import sys, json data = json.load(sys.stdin) print(f"Overall: {data['state']}") for s in data.get('statuses', []): print(f" {s['context']}: {s['state']} - {s.get('description', '')}")"
Also check GitHub Actions check runs (separate endpoint)
同时检查GitHub Actions的检查运行情况(独立接口)
curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/check-runs
| python3 -c " import sys, json data = json.load(sys.stdin) for cr in data.get('check_runs', []): print(f" {cr['name']}: {cr['status']} / {cr['conclusion'] or 'pending'}")"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/check-runs
| python3 -c " import sys, json data = json.load(sys.stdin) for cr in data.get('check_runs', []): print(f" {cr['name']}: {cr['status']} / {cr['conclusion'] or 'pending'}")"
undefinedcurl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/check-runs
| python3 -c " import sys, json data = json.load(sys.stdin) for cr in data.get('check_runs', []): print(f" {cr['name']}: {cr['status']} / {cr['conclusion'] or 'pending'}")"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/check-runs
| python3 -c " import sys, json data = json.load(sys.stdin) for cr in data.get('check_runs', []): print(f" {cr['name']}: {cr['status']} / {cr['conclusion'] or 'pending'}")"
undefinedPoll Until Complete (git + curl)
持续轮询直到完成(git + curl)
bash
undefinedbash
undefinedSimple polling loop — check every 30 seconds, up to 10 minutes
简单轮询循环——每30秒检查一次,最多持续10分钟
SHA=$(git rev-parse HEAD)
for i in $(seq 1 20); do
STATUS=$(curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c "import sys,json; print(json.load(sys.stdin)['state'])") echo "Check $i: $STATUS" if [ "$STATUS" = "success" ] || [ "$STATUS" = "failure" ] || [ "$STATUS" = "error" ]; then break fi sleep 30 done
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c "import sys,json; print(json.load(sys.stdin)['state'])") echo "Check $i: $STATUS" if [ "$STATUS" = "success" ] || [ "$STATUS" = "failure" ] || [ "$STATUS" = "error" ]; then break fi sleep 30 done
undefinedSHA=$(git rev-parse HEAD)
for i in $(seq 1 20); do
STATUS=$(curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c "import sys,json; print(json.load(sys.stdin)['state'])") echo "Check $i: $STATUS" if [ "$STATUS" = "success" ] || [ "$STATUS" = "failure" ] || [ "$STATUS" = "error" ]; then break fi sleep 30 done
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/commits/$SHA/status
| python3 -c "import sys,json; print(json.load(sys.stdin)['state'])") echo "Check $i: $STATUS" if [ "$STATUS" = "success" ] || [ "$STATUS" = "failure" ] || [ "$STATUS" = "error" ]; then break fi sleep 30 done
undefined5. Auto-Fixing CI Failures
5. 自动修复CI失败
When CI fails, diagnose and fix. This loop works with either auth method.
当CI失败时,诊断问题并修复。以下循环适用于两种认证方式。
Step 1: Get Failure Details
步骤1:获取失败详情
With gh:
bash
undefined使用gh:
bash
undefinedList recent workflow runs on this branch
列出当前分支最近的工作流运行记录
gh run list --branch $(git branch --show-current) --limit 5
gh run list --branch $(git branch --show-current) --limit 5
View failed logs
查看失败日志
gh run view <RUN_ID> --log-failed
**With git + curl:**
```bash
BRANCH=$(git branch --show-current)gh run view <RUN_ID> --log-failed
**使用git + curl:**
```bash
BRANCH=$(git branch --show-current)List workflow runs on this branch
列出当前分支的工作流运行记录
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?branch=$BRANCH&per_page=5"
| python3 -c " import sys, json runs = json.load(sys.stdin)['workflow_runs'] for r in runs: print(f"Run {r['id']}: {r['name']} - {r['conclusion'] or r['status']}")"
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?branch=$BRANCH&per_page=5"
| python3 -c " import sys, json runs = json.load(sys.stdin)['workflow_runs'] for r in runs: print(f"Run {r['id']}: {r['name']} - {r['conclusion'] or r['status']}")"
curl -s
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?branch=$BRANCH&per_page=5"
| python3 -c " import sys, json runs = json.load(sys.stdin)['workflow_runs'] for r in runs: print(f"Run {r['id']}: {r['name']} - {r['conclusion'] or r['status']}")"
-H "Authorization: token $GITHUB_TOKEN"
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?branch=$BRANCH&per_page=5"
| python3 -c " import sys, json runs = json.load(sys.stdin)['workflow_runs'] for r in runs: print(f"Run {r['id']}: {r['name']} - {r['conclusion'] or r['status']}")"
Get failed job logs (download as zip, extract, read)
获取失败任务的日志(下载为zip包,解压后查看)
RUN_ID=<run_id>
curl -s -L
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/logs
-o /tmp/ci-logs.zip cd /tmp && unzip -o ci-logs.zip -d ci-logs && cat ci-logs/*.txt
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/logs
-o /tmp/ci-logs.zip cd /tmp && unzip -o ci-logs.zip -d ci-logs && cat ci-logs/*.txt
undefinedRUN_ID=<run_id>
curl -s -L
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/logs
-o /tmp/ci-logs.zip cd /tmp && unzip -o ci-logs.zip -d ci-logs && cat ci-logs/*.txt
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/logs
-o /tmp/ci-logs.zip cd /tmp && unzip -o ci-logs.zip -d ci-logs && cat ci-logs/*.txt
undefinedStep 2: Fix and Push
步骤2:修复并推送
After identifying the issue, use file tools (, ) to fix it:
patchwrite_filebash
git add <fixed_files>
git commit -m "fix: resolve CI failure in <check_name>"
git push定位问题后,使用文件工具(、)修复代码:
patchwrite_filebash
git add <fixed_files>
git commit -m "fix: resolve CI failure in <check_name>"
git pushStep 3: Verify
步骤3:验证
Re-check CI status using the commands from Section 4 above.
使用第4节中的命令重新检查CI状态。
Auto-Fix Loop Pattern
自动修复循环模式
When asked to auto-fix CI, follow this loop:
- Check CI status → identify failures
- Read failure logs → understand the error
- Use +
read_file/patch→ fix the codewrite_file git add . && git commit -m "fix: ..." && git push- Wait for CI → re-check status
- Repeat if still failing (up to 3 attempts, then ask the user)
当需要自动修复CI时,请遵循以下循环:
- 检查CI状态 → 定位失败项
- 查看失败日志 → 理解错误原因
- 使用+
read_file/patch→ 修复代码write_file git add . && git commit -m "fix: ..." && git push- 等待CI运行 → 重新检查状态
- 若仍失败则重复操作(最多3次,之后询问用户)
6. Merging
6. 合并PR
With gh:
bash
undefined使用gh:
bash
undefinedSquash merge + delete branch (cleanest for feature branches)
压缩合并 + 删除分支(功能分支的最优方式)
gh pr merge --squash --delete-branch
gh pr merge --squash --delete-branch
Enable auto-merge (merges when all checks pass)
启用自动合并(所有检查通过后自动合并)
gh pr merge --auto --squash --delete-branch
**With git + curl:**
```bash
PR_NUMBER=<number>gh pr merge --auto --squash --delete-branch
**使用git + curl:**
```bash
PR_NUMBER=<number>Merge the PR via API (squash)
通过API合并PR(压缩合并)
curl -s -X PUT
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/merge
-d "{ "merge_method": "squash", "commit_title": "feat: add user authentication (#$PR_NUMBER)" }"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/merge
-d "{ "merge_method": "squash", "commit_title": "feat: add user authentication (#$PR_NUMBER)" }"
curl -s -X PUT
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/merge
-d "{ "merge_method": "squash", "commit_title": "feat: add user authentication (#$PR_NUMBER)" }"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/merge
-d "{ "merge_method": "squash", "commit_title": "feat: add user authentication (#$PR_NUMBER)" }"
Delete the remote branch after merge
合并后删除远程分支
BRANCH=$(git branch --show-current)
git push origin --delete $BRANCH
BRANCH=$(git branch --show-current)
git push origin --delete $BRANCH
Switch back to main locally
本地切换回main分支
git checkout main && git pull origin main
git branch -d $BRANCH
Merge methods: `"merge"` (merge commit), `"squash"`, `"rebase"`git checkout main && git pull origin main
git branch -d $BRANCH
合并方式:`"merge"`(创建合并提交)、`"squash"`(压缩合并)、`"rebase"`(变基合并)Enable Auto-Merge (curl)
启用自动合并(curl)
bash
undefinedbash
undefinedAuto-merge requires the repo to have it enabled in settings.
启用自动合并需要仓库在设置中开启该功能。
This uses the GraphQL API since REST doesn't support auto-merge.
由于REST API不支持自动合并,此处使用GraphQL API。
PR_NODE_ID=$(curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER
| python3 -c "import sys,json; print(json.load(sys.stdin)['node_id'])")
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER
| python3 -c "import sys,json; print(json.load(sys.stdin)['node_id'])")
curl -s -X POST
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/graphql
-d "{"query": "mutation { enablePullRequestAutoMerge(input: {pullRequestId: \"$PR_NODE_ID\", mergeMethod: SQUASH}) { clientMutationId } }"}"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/graphql
-d "{"query": "mutation { enablePullRequestAutoMerge(input: {pullRequestId: \"$PR_NODE_ID\", mergeMethod: SQUASH}) { clientMutationId } }"}"
undefinedPR_NODE_ID=$(curl -s
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER
| python3 -c "import sys,json; print(json.load(sys.stdin)['node_id'])")
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER
| python3 -c "import sys,json; print(json.load(sys.stdin)['node_id'])")
curl -s -X POST
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/graphql
-d "{"query": "mutation { enablePullRequestAutoMerge(input: {pullRequestId: \"$PR_NODE_ID\", mergeMethod: SQUASH}) { clientMutationId } }"}"
-H "Authorization: token $GITHUB_TOKEN"
https://api.github.com/graphql
-d "{"query": "mutation { enablePullRequestAutoMerge(input: {pullRequestId: \"$PR_NODE_ID\", mergeMethod: SQUASH}) { clientMutationId } }"}"
undefined7. Complete Workflow Example
7. 完整工作流程示例
bash
undefinedbash
undefined1. Start from clean main
1. 从干净的main分支开始
git checkout main && git pull origin main
git checkout main && git pull origin main
2. Branch
2. 创建分支
git checkout -b fix/login-redirect-bug
git checkout -b fix/login-redirect-bug
3. (Agent makes code changes with file tools)
3. (代理使用文件工具修改代码)
4. Commit
4. 提交代码
git add src/auth/login.py tests/test_login.py
git commit -m "fix: correct redirect URL after login
Preserves the ?next= parameter instead of always redirecting to /dashboard."
git add src/auth/login.py tests/test_login.py
git commit -m "fix: correct redirect URL after login
Preserves the ?next= parameter instead of always redirecting to /dashboard."
5. Push
5. 推送分支
git push -u origin HEAD
git push -u origin HEAD
6. Create PR (picks gh or curl based on what's available)
6. 创建PR(根据可用工具选择gh或curl)
... (see Section 3)
...(参考第3节)
7. Monitor CI (see Section 4)
7. 监控CI状态(参考第4节)
8. Merge when green (see Section 6)
8. 检查通过后合并(参考第6节)
undefinedundefinedUseful PR Commands Reference
实用PR命令参考
| Action | gh | git + curl |
|---|---|---|
| List my PRs | | |
| View PR diff | | |
| Add comment | | |
| Request review | | |
| Close PR | | |
| Check out someone's PR | | |
| 操作 | gh | git + curl |
|---|---|---|
| 列出我的PR | | |
| 查看PR差异 | | |
| 添加评论 | | |
| 请求审核 | | |
| 关闭PR | | |
| 检出他人的PR | | |