github-workflows/skills/squash-merge-pr/SKILL.md
Squash-merge a PR into main. Invoke only when the user explicitly requests a squash merge. Single PR by number or current branch.
npx skillsauth add jacobpevans/claude-code-plugins squash-merge-prInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Validates readiness, invokes /finalize-pr for soft blocks, then squash-merges.
Hard stops abort immediately. Some cases require human action: closed/merged PR,
draft, unresolvable conflicts, unrecoverable CI, or more than 100 review threads.
State warning: Branch state, remote tracking, and PR status change between invocations. Re-run all git/gh commands from Step 1.
/finalize-pr's responsibility/finalize-pr for soft blocks; abort on hard stops with reasonRun the canonical PR-readiness gate and canonical code-scanning alert count
from /gh-cli-patterns. Replace <OWNER>, <REPO>, <PR_NUMBER> per the
placeholder convention. CodeQL is separate from CI — check both.
| Condition | Message |
|-----------|---------|
| state != OPEN | "PR is closed or merged — nothing to do" |
| isDraft == true | "PR is a draft — mark it ready for review first" |
| reviewThreads.pageInfo.hasNextPage == true | ">100 review threads — paginate manually and re-verify before merging" |
If any of the following fail, proceed to Step 1.3 (auto-finalize), then re-run the full gate. If the gate still fails after finalization, abort with the specific reason.
| Check | Must be | Abort message (if still failing after finalize) |
|-------|---------|------------------------------------------------|
| mergeable | MERGEABLE | "PR has git conflicts — unresolvable" |
| mergeStateStatus | CLEAN or HAS_HOOKS | "PR merge state is {value} — still blocked after finalize" |
| reviewDecision | APPROVED or null | "Review decision is {value}" |
| statusCheckRollup.state | SUCCESS | "CI is {state} — unrecoverable" |
| All reviewThreads.isResolved | true | "Unresolved review threads remain" |
| CodeQL alert count | 0 | "Open CodeQL alerts remain — run /resolve-codeql manually" |
Invoke /finalize-pr <PR_NUMBER>. If it reports human intervention needed, abort with
its reason. Then re-run the full gate (Steps 1.1 + 1.2); if any soft block persists,
abort with the specific failing field.
Analyze the full changeset to generate a release-note-friendly commit message.
Replace <PR_NUMBER> before running:
git fetch origin main
git diff origin/main...HEAD
git log --oneline origin/main..HEAD
Generate:
<type>: <description>, under 70 chars)Types: feat, fix, refactor, docs, test, chore
Store the title in a shell variable:
SQUASH_TITLE="<generated title>"
Capture the branch name before merging (needed for cleanup). Replace <PR_NUMBER> before running:
BRANCH=$(gh pr view <PR_NUMBER> --json headRefName --jq '.headRefName')
Merge without --delete-branch (avoids git switch failure in bare+worktree repos).
Use the heredoc body pattern from /gh-cli-patterns:
gh pr merge <PR_NUMBER> --squash --subject "$SQUASH_TITLE" --body "$(cat <<'EOF'
... generated body ...
EOF
)"
Single-quoted 'EOF' prevents shell expansion. Closing EOF must be alone on its own line with no leading whitespace.
Delete the remote branch (GitHub may have auto-deleted it on merge — || true handles that):
git push origin --delete "$BRANCH" || true
Find and remove the local worktree by branch name (works in any repo layout):
WORKTREE_PATH=$(git worktree list --porcelain | awk -v b="refs/heads/$BRANCH" '/^worktree/{p=$2} $0=="branch "b{print p}')
[ -n "$WORKTREE_PATH" ] && git worktree remove "$WORKTREE_PATH" || true
Delete the local branch ref (safe no-op if absent):
git branch -d "$BRANCH" || true
git switch main
git pull origin main
git worktree prune
Invoke at any time — auto-finalizes if needed:
/squash-merge-pr # Current branch PR
/squash-merge-pr 42 # Specific PR number
tools
Use when installing or choosing CLI tools in a Nix flake repo, editing flake.nix or home-manager config, or when tempted to pip/pipx/uv/brew/npm install anything. Tools come from the dev shell or nix shell — never ad-hoc package managers.
testing
Use when creating or editing GitHub Actions workflows that call reusable workflows (uses: OWNER/repo/.github/workflows/...) — org owner references must be the literal current org, and shared-CI homes are under dryvist.
development
Use when adding or editing .pre-commit-config.yaml, wiring pre-commit hooks into a repo, scaffolding a new repo's lint/hook setup, or deciding where a hook or shared lint config should live. Covers the canonical nix-devenv/dryvist-.github architecture, profiles, and consumer patterns.
testing
Check PR merge readiness, sync local repo, cleanup stale worktrees; optional cross-repo sweep and stale-branch prune modes