| name | github-pr-workflow |
| description | GitHub PR lifecycle: branch, commit, open, CI, merge. |
| version | 1.5.0 |
| author | Hermes Agent |
| license | MIT |
| metadata | {"hermes":{"tags":["GitHub","Pull-Requests","CI/CD","Git","Automation","Merge"],"related_skills":["github-auth","github-code-review"]}} |
GitHub Pull Request Workflow
Complete guide for managing the PR lifecycle. Each section shows the gh way first, then the git + curl fallback for machines without gh.
Prerequisites
- Authenticated with GitHub (see
github-auth skill)
- Inside a git repository with a GitHub remote
Quick Auth Detection
if command -v gh &>/dev/null && gh auth status &>/dev/null; then
AUTH="gh"
else
AUTH="git"
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"
Extracting Owner/Repo from the Git Remote
Many curl commands need owner/repo. Extract it from the git remote:
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
This part is pure git — identical either way:
git fetch origin
git checkout main && git pull origin main
git checkout -b feat/add-user-authentication
Branching model note: This workflow assumes feature → main direct (no integration branch). If your team uses feature → dev → main, branch from dev instead. See references/branching-models.md for both models, migration guide, and when to use each.
Branch naming conventions:
feat/description — new features
fix/description — bug fixes
refactor/description — code restructuring
docs/description — documentation
ci/description — CI/CD changes
2. Making Commits
Pitfall 1: Files Ignored by .gitignore (can't stage)
Some config files (e.g., home/config.yaml) are in .gitignore because they contain API keys or are machine-specific. If you need to commit a structural configuration change (like toolset definitions) that is not a secret, git add will silently skip it — no error, no warning, and the file won't appear in git status.
Detect: If git diff <file> and git status <file> show nothing but you know the file was modified, check .gitignore:
git ls-files <file>
git check-ignore -v <file>
Fix: Force-track with -f:
git add -f path/to/ignored-file.yaml
Caution: Only force-track files whose content you've reviewed. Never force-add files that contain real secrets (hardcoded passwords, API keys as literal values). Files using ${ENV_VAR} references for secrets are safe to track.
Pitfall 2: Already-tracked files still staged despite .gitignore
Adding a file to .gitignore does NOT stop git from tracking changes to it if it was already committed. git add -A will happily stage modifications to a tracked file that matches .gitignore rules. This is a common source of accidentally committed secrets or runtime configs.
Detect: After staging, check for files that should be gitignored but appear in the diff:
git diff --cached --name-only
git ls-files path/to/file.yaml
Fix: Remove from the index (keeps the local file):
git rm --cached path/to/local-config.yaml
git commit -m "chore: stop tracking local config (already in .gitignore)"
After git rm --cached, future git add -A will correctly skip the file.
Pitfall 3: Untracked runtime files staged by git add -A
When a project has accumulated runtime artifacts (SQLite databases, caches, session state, JSON dumps) that aren't in .gitignore, git add -A stages everything indiscriminately. Before committing any bulk staging:
- Audit untracked files before staging — run
git status --short and review ?? entries for runtime state
- Update
.gitignore first — add patterns for any runtime files/dirs discovered (e.g., *.db, cache/, hindsight/, state-snapshots/, .curator_state)
- Then
git add -A — newly gitignored files won't appear
Common runtime artifacts to exclude:
kanban.db, *.db-shm, *.db-wal — local databases
cache/, state-snapshots/ — derived/cached data
hindsight/, *.lock — session/temp state
*.restart_*.json, .curator_state — daemon/runtime metadata
- Per-profile configs with API keys or machine-specific settings
Use the agent's file tools (write_file, patch) to make changes, then commit:
Before git add -A: audit untracked files for runtime state (see Pitfall 3). Update .gitignore first if needed, and git rm --cached any tracked files that should be gitignored (see Pitfall 2).
git add src/auth.py src/models/user.py tests/test_auth.py
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
3. Pushing and Creating a PR
Push the Branch (same either way)
git push -u origin HEAD
Create the PR
With gh:
gh pr create \
--title "feat: add JWT-based user authentication" \
--body "## Summary
- Adds login and register API endpoints
- JWT token generation and validation
## Test Plan
- [ ] Unit tests pass
Closes #42"
Options: --draft, --reviewer user1,user2, --label "enhancement", --base develop
With git + curl:
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 number — save it for later commands.
To create as a draft, add "draft": true to the JSON body.
4. Monitoring CI Status
Check CI Status
With gh:
gh pr checks
gh pr checks --watch
With git + curl:
SHA=$(git rev-parse HEAD)
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', '')}\")"
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'}\")"
Poll Until Complete (git + curl)
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
Detecting Pre-existing CI Failures (Not Introduced by the PR)
When reviewing multiple PRs and all show the same CI failure pattern, verify whether the failure already exists on main before writing the PR off:
gh run list --branch main --limit 1 --json conclusion,workflowName
gh run view <RUN_ID> --log-failed | grep -E "error|failure|exit code" | head -10
gh pr checks <PR_NUMBER> --json name,description,state
Decision logic for pre-existing failures:
| Main CI | PR CI | Assessment |
|---|
| ✅ passing | ❌ failing | Likely introduced by PR — do NOT merge until fixed |
| ❌ failing | ❌ failing (same error) | Pre-existing — failure existed before the PR. Safe to merge if PR changes are orthogonal to the failing checks |
| ❌ failing | ✅ passing | PR fixed or bypassed a broken check — unusual, verify manually |
| ❌ failing | ❌ failing (different error) | Mixed — verify PR didn't add new failures on top of pre-existing ones |
Confirming orthogonality: If the PR touches only docs, config templates, setup scripts, or skill files — and the CI failure is a lint error in src/ or a unit test in a module the PR never touched — the failure is orthogonal and pre-existing.
Pitfall — don't merge when in doubt: If you can't tell whether the CI failure is pre-existing or introduced, treat it as blocking. Run the failing CI step on the PR branch directly (gh run view --log-failed) and compare the error to a fresh run on main.
5. Auto-Fixing CI Failures
When CI fails, diagnose and fix. This loop works with either auth method.
Step 1: Get Failure Details
With gh:
gh run list --branch $(git branch --show-current) --limit 5
gh run view <RUN_ID> --log-failed
With git + curl:
BRANCH=$(git branch --show-current)
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']}\")"
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
Step 2: Fix and Push
After identifying the issue, use file tools (patch, write_file) to fix it:
git add <fixed_files>
git commit -m "fix: resolve CI failure in <check_name>"
git push
Step 3: Verify
Re-check CI status using the commands from Section 4 above.
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/write_file → fix the code
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)
6. Merging
With gh:
gh pr merge --squash --delete-branch
gh pr merge --auto --squash --delete-branch
With git + curl:
PR_NUMBER=<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)\"
}"
BRANCH=$(git branch --show-current)
git push origin --delete $BRANCH
git checkout main && git pull origin main
git branch -d $BRANCH
Merge methods: "merge" (merge commit), "squash", "rebase"
Enable Auto-Merge (curl)
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'])")\n
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 } }\"}"
Pitfalls
Cannot approve your own pull request
gh pr review --approve fails with: GraphQL: Review Can not approve your own pull request. This happens when the authenticated GitHub user is also the PR author.
Solution: If you have merge permissions on the repo and no external review is required by branch protection rules, skip the approval step entirely and proceed directly to merge:
gh pr merge N --squash --delete-branch
Detection: Before attempting approve, check if the PR author matches the authenticated user:
PR_AUTHOR=$(gh pr view N --json author --jq .author.login)
GH_USER=$(gh api user --jq .login)
if [ "$PR_AUTHOR" = "$GH_USER" ]; then
echo "Self-PR detected: skipping approval, merging directly"
gh pr merge N --squash --delete-branch
else
gh pr review N --approve
gh pr merge N --squash --delete-branch
fi
gh pr merge with local working tree changes
When there are local uncommitted modifications, gh pr merge may produce a confusing partial result:
- ✅ The remote merge succeeds via the GitHub API — the PR is merged on GitHub
- ❌ The local git operations fail —
git checkout, branch deletion, and git pull all abort
- The remote branch is NOT deleted (--delete-branch never executed)
- The PR state shows
MERGED but the local repo is on the old branch with dirty state
Fix — before merging: Always check and stash local changes first:
if [ -n "$(git status --porcelain)" ]; then
git stash push -m "pre-merge-autostash"
gh pr merge N --squash --delete-branch
git stash pop
else
gh pr merge N --squash --delete-branch
fi
Recovery if you already merged and the local step failed:
git push origin --delete <feature-branch>
git stash
git checkout main
git pull origin main
git stash pop
git fetch --prune origin
7. Complete Workflow Example
git checkout main && git pull origin main
git checkout -b fix/login-redirect-bug
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 push -u origin HEAD
8. Release Workflow
Complete versioned release pipeline: branch → changes → commit → tag → PR → merge → release.
Branch and Version Bump
git checkout main && git pull origin main
git checkout -b release/v0.8.0
git add pyproject.toml CHANGELOG.md AGENTS.md README.md scripts/ Makefile
git commit -m "release: v0.8.0 — automated setup scripts, docs overhaul"
Tag and Push
git tag v0.8.0
git push origin release/v0.8.0 --tags
Create PR and Merge
gh pr create \
--base main \
--head release/v0.8.0 \
--title "release: v0.8.0 — description" \
--body "## v0.8.0 — Title
### What's New
- feat: new feature description
### Breaking Changes
- None (or description)
### Migration from v0.7.x
- Run bash scripts/setup.sh"
gh pr merge 25 --squash --delete-branch
Create GitHub Release
gh release create v0.8.0 \
--title "v0.8.0 — Title" \
--notes "## v0.8.0 — Title
### Quick Start
\`\`\`bash
git clone https://github.com/OWNER/REPO.git
cd REPO
bash scripts/setup.sh
\`\`\`
### What's New
- bullet points
### Upgrade from v0.7.x
- Migration instructions"
Post-Release Cleanup
git checkout main
git pull origin main
git branch -d release/v0.8.0
Pre-Release Documentation Audit
After any release that removes files, changes installation method, moves paths, or deprecates commands, run a string audit BEFORE tagging. This is a scoped version of the general post-migration audit (see autonomous-ai-agents/hermes-agent/references/post-migration-audit.md for the full methodology).
Quick audit — version consistency and dangling references:
git ls-files | xargs grep -l 'configure\.sh\|start\.sh\|olympus_v2\|\.pi-daimons\|~/.hermes/' 2>/dev/null
grep -rn '/home/[^/]\+/Aether-Agents' --include='*.md' --include='*.yaml' --include='*.html' 2>/dev/null | grep -v '.template'
grep 'version' pyproject.toml | head -1
grep 'version-' README.md | head -1
grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' CHANGELOG.md | head -1
grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' Makefile scripts/setup.sh | sort | uniq -c
grep -rn 'uses:.*@v[0-9]' .github/workflows/
grep -rn 'pip install -e \.\|configure\.sh\|start\.sh\|~/.hermes/' website/ 2>/dev/null
Full migration audit — after path changes, convention shifts, or module renames:
For major refactoring (.eter/ → .aether/, profile restructuring, script renaming), follow the comprehensive post-migration audit methodology: catalog old conventions, grep for each pattern, classify by priority (functional code > agent configs > docs > CHANGELOG), fix in order, migrate on-disk state, verify clean. See references/post-migration-audit.md in the hermes-agent skill.
Fix all findings, commit, then proceed with tagging.
Pitfalls
- Never
git add -A: Stage specific files only. Repos with runtime data (databases, sessions, caches, local configs) will stage everything. Use git add <file1> <file2> ... or git diff --cached --stat to review before committing.
- Version must match everywhere: pyproject.toml, CHANGELOG.md, AGENTS.md (versioning section), README.md (badge). Miss any one and the release is inconsistent.
- Tag after commit: Create the tag AFTER the commit is made, not before. The tag points to the commit hash.
- Squash merge for releases: Use
--squash --delete-branch for release PRs. This keeps main history clean with a single commit per release. Feature branches can use regular merge if needed.
- Dangling references after cleanup: When removing deprecated files (scripts, code dirs, docs), always audit for references in README, website, and remaining docs. Deleted code leaves ghost references that confuse new users.
- Merging with uncommitted local changes:
git checkout or git merge will abort if local modifications would be overwritten. Always git status --short before branch operations. Stash (git stash push), commit, or discard changes first. See references/branching-models.md for the full pattern.
|- Backup recovery with wrong directory structure: When cherry-picking from an old backup branch, the directory structure may have changed (e.g., home/skills/ in backup vs skills/ in current HEAD). Extract content to the CURRENT structure, not the backup's structure. Verify destination paths before writing. See references/branching-models.md.
Pitfall #N — GitHub Self-Approve Not Possible for Same-Author PRs
Síntoma: Ejecutas gh pr review <N> --approve en un PR abierto por ti mismo (DarkArty07). GitHub rechaza con error gh: Cannot approve your own pull request. El merge con gh pr merge --squash SÍ funciona sin aprobación, pero queda sin audit trail de review.
Por qué: Regla de GitHub — un usuario no puede aprobar su propio PR. gh pr review --approve falla con 422 si el revisor es el autor.
Opciones para batch self-merge:
-
Aceptar el merge sin aprobación (lo que hicimos en sesión 06-04 con 5 PRs):
gh pr merge <N> --squash --delete-branch
Funciona si el PR es MERGEABLE y la branch protection no requiere review. Si requiere review, este comando falla con "Reviews required".
-
Configurar branch protection para permitir merge sin review (recomendado para repo personal):
- Settings → Branches → main → Edit → "Require pull request reviews before merging" → OFF
- Permite merge directo sin approvals
-
Habilitar auto-approve con ruleset + GitHub Actions (más limpio):
- Crear
.github/workflows/auto-approve.yml que aprueba PRs del owner
- Útil si trabajas con colaboradores externos que necesiten review humano
Para repos personales de un solo owner (caso de Aether): Opción 2 es la más limpia. Un solo toggle, sin CI, sin reglas.
Cuándo SÍ requerir review humano: Repo con colaboradores externos, código de producción sensible, cambios en CI/CD.
Audit trail alternativo: Si quieres saber que "alguien revisó" sin aprobación humana, usa gh pr view <N> --json reviews,comments post-merge para extraer el diff y los comentarios dejados. Pero sin gh pr review --approve, no hay línea formal de aprobación.
Pitfall #N — Pre-Existing CI Failures Don't Block Merge of Unrelated PRs
Síntoma: Tu repo tiene CI rojo en main (ej. Ruff lint con 28 errores en src/olympus_v3/server.py que ya existían antes de tu PR). Quieres mergear 5 PRs que NO tocan src/ — solo tocan home/skills/, docs/, scripts/, CHANGELOG.md. La tentación es no mergear ninguno hasta arreglar el lint.
Decisión correcta: Mergear las PRs que no tocan src/ y arreglar el lint en una PR separada de cleanup.
Por qué:
- El CI rojo pre-existente en main no fue introducido por tus PRs. Mergearlas no empeora nada.
- Bloquear features/docs/fixes legítimos por tech debt de lint es contraproducente.
- Una PR de cleanup dedicada (e.g.
feature/fix-ruff-lint-server) es más fácil de revisar que un mega-PR que mezcla features con refactors de lint.
Cómo identificar si el CI failure es pre-existente:
git checkout main
gh pr checks <PR_NUMBER> 2>&1 | head -20
git checkout main
.venv-hermes/bin/python -m ruff check src/X.py
Política recomendada para repo personal:
- CI rojo pre-existente en main: OK mergear PRs que no tocan el código en rojo
- CI rojo en una PR: NO mergear, fix en la misma PR
- CI amarillo (warnings, no errors): OK mergear
Naming convention para la PR de cleanup: feature/fix-ruff-lint-<module> o chore/fix-pre-existing-lint para que sea buscable después.
9. Merge Conflict Resolution
When git merge (or git pull which runs merge) encounters conflicting changes, git pauses and marks files as unmerged. The merge is incomplete — you must resolve before committing.
9.1 Detecting Conflicts
After a merge attempt:
git status
Look for these indicators:
| Status | Meaning |
|---|
both modified: <file> | modify/modify — same file changed in both branches |
both added: <file> | add/add — same file created in both branches |
deleted by us: <file> | deleted on current branch, modified on theirs |
deleted by them: <file> | modified on current branch, deleted on theirs |
Unmerged paths: section | Summary of files needing resolution |
All conflicts fixed but you are still merging. | All marked resolved, ready to commit |
9.2 Ours vs Theirs Semantics
During git merge <other> while on current-branch:
- Ours =
current-branch (the branch you're merging INTO)
- Theirs =
<other> (the branch being merged FROM)
git checkout --ours path/to/file
git checkout --theirs path/to/file
CRITICAL: These flags only work for files listed under Unmerged paths. For files listed under Changes not staged for commit (unstaged modifications that aren't part of the conflict), use git checkout origin/main -- path/to/file to reset to the remote's version.
9.3 Add/Add Conflicts (Both Added)
This happens when the same file was created independently in both branches. Neither side may have the full content. Always inspect both versions:
git checkout --ours path/to/file
git checkout --theirs path/to/file
Manual union strategy: When neither side alone has the complete desired content (e.g., each PR added different tests in the same file), you must manually construct the union:
- Start with one version (
--theirs or --ours) as the base
- Use
patch/write_file to add the missing content from the other side
- Verify the result (e.g.,
grep -c "def test_" to confirm total test count)
- Stage with
git add
9.4 Modify/Modify Conflicts
Same file changed differently in both branches. The file on disk contains merge conflict markers:
<<<<<<< HEAD
// our version (current branch)
=======
// their version (branch being merged)
>>>>>>> branch-name
Resolution options:
git checkout --ours path/to/file
git checkout --theirs path/to/file
9.5 Verification After Resolution
Always verify the resolved file has correct content before staging:
grep -c "^def test_" tests/test_file.py
grep -rn "<<<<<<< \|=======\|>>>>>>>" path/to/file
grep "specific_function_or_import" path/to/file
git diff path/to/file
9.6 Staging and Committing
git add path/to/file1 path/to/file2
git status
git diff --cached --name-status
git commit --no-edit
git commit -m "Merge branch 'main' into feature/my-feature"
Pitfall: Task descriptions may be wrong about ours/theirs
Always verify the actual state on disk rather than blindly trusting instructions. The task may say --theirs but the context may contradict it. Cross-check:
- Check actual conflict type from
git status
- Inspect both versions (
--ours then --theirs)
- Verify the resolved content has what you expect before staging
Pitfall: Add/add conflicts may require manual union
Neither side may be "correct" — both branches may have added different subsets of the same logical file. The guardrail "if checkout resolves to wrong version, stop" is useful, but the better response is to manually merge both versions rather than reporting failure.
Pitfall: "Changes not staged for commit" vs "Unmerged paths"
A file showing as modified under "Changes not staged for commit" during a merge is NOT part of the conflict — it's an unrelated working-tree change. Do NOT use git checkout --ours/--theirs on it. Use git checkout origin/main -- <file> to reset it.
Useful PR Commands Reference
| Action | gh | git + curl |
|---|
| List my PRs | gh pr list --author @me | curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$OWNER/$REPO/pulls?state=open" |
| View PR diff | gh pr diff | git diff main...HEAD (local) or curl -H "Accept: application/vnd.github.diff" ... |
| Add comment | gh pr comment N --body "..." | curl -X POST .../issues/N/comments -d '{"body":"..."}' |
| Request review | gh pr edit N --add-reviewer user | curl -X POST .../pulls/N/requested_reviewers -d '{"reviewers":["user"]}' |
| Close PR | gh pr close N | curl -X PATCH .../pulls/N -d '{"state":"closed"}' |
| Check out someone's PR | gh pr checkout N | git fetch origin pull/N/head:pr-N && git checkout pr-N |
References
references/conventional-commits.md — Commit message format and type reference
references/ci-troubleshooting.md — Common CI failure patterns and fixes
references/branching-models.md — When to use feature → dev → main vs feature → main, migration guide, stash patterns, and backup recovery pitfalls
references/smoke-testing-setup-scripts.md — Single-PR fresh-clone smoke test for setup script changes
references/multi-pr-smoke-test-remote.md — Multi-PR consolidated smoke test on a remote machine via SSH; check() function pattern, submodule cloning pitfalls, eval + cd side effects, exec > >(tee) buffering over SSH, and broad grep false positives
references/batch-pr-cleanup.md — Multi-PR autonomous sweep checklist: discovery, classification, self-approval bypass, pre-existing CI detection, batch execution, post-merge sync, and anti-patterns