Merges pull requests using squash merge with proper validation and cleanup
Squash merge pull requests with full validation. Verifies PR title/description accuracy, CI checks, and mergeable status before merging. Automatically cleans up branches and updates session purpose after successful merge.
/plugin marketplace add zookanalytics/claude-devcontainer/plugin install git-workflow@claude-devcontainerUser-provided context: $ARGUMENTS
If user provided a PR number in arguments: Use that PR number.
If no PR number provided: Automatically determine from current branch:
git branch --show-current
gh pr list --head <branch-name> --json number --jq '.[0].number'
branch-name"Use TodoWrite to create todos for EACH validation step.
Run both queries in parallel (no dependencies between them):
# Query 1: Get all PR data in one call (includes headRefName for branch)
gh pr view <number> --json number,title,body,statusCheckRollup,mergeable,headRefName
# Query 2: Get commit history for description verification
# Use PR branch name (headRefName) to ensure correct history regardless of current branch
git log origin/main..origin/<headRefName> --oneline
Reference the pull-request-conventions skill for title format.
Check format: <type>[optional scope]: <description>
The title becomes the squashed commit message on main.
Foundational principle: Description must be 100% accurate. No exceptions.
Use the body from Step 1 and commit history from Step 1.
If description mentions specific features, approaches, or code changes, verify with diff:
gh pr diff <number>
Reference the pull-request-conventions skill for description requirements.
Red flags that block merge:
If ANY red flags found - DO NOT MERGE:
gh pr edit <number> --body "$(cat <<'EOF'
## Summary
<corrected description reflecting actual changes>
## Test plan
<verification steps>
EOF
)"
Use statusCheckRollup from Step 1.
All checks must show one of:
"conclusion": "SUCCESS" and "status": "COMPLETED" (passed)"conclusion": null and "status": "SKIPPED" (legitimately skipped)If any checks show SKIPPED: Verify it's intentional (conditional workflows, platform-specific tests).
If any checks failed:
CRITICAL: GitHub computes mergeability asynchronously. Always verify before merge.
Use mergeable from Step 1.
Expected states:
"mergeable": "MERGEABLE" - Ready to merge"mergeable": "CONFLICTING" - Has conflicts, cannot merge"mergeable": "UNKNOWN" - GitHub still computing, must waitIf status is UNKNOWN:
GitHub hasn't computed mergeability yet. This commonly happens after:
Wait and retry (up to 3 attempts, 5 seconds apart):
# Check status
gh pr view <number> --json mergeable --jq '.mergeable'
# If UNKNOWN, wait 5 seconds and check again
sleep 5
gh pr view <number> --json mergeable --jq '.mergeable'
If still UNKNOWN after 3 attempts:
If CONFLICTING:
Always use squash merge:
gh pr merge <number> --squash
Why squash merge:
gh pr view <number> --json mergeable,mergeStateStatus
Common failures:
Merge conflicts - "mergeable": "CONFLICTING"
Branch protection violations
Insufficient permissions
DO NOT attempt to resolve merge failures without user input.
After successful merge, IMMEDIATELY clean up:
# 1. Verify merge succeeded
gh pr view <number> --json state,mergedAt
# 2. Switch to main and pull (sequential - must complete before cleanup)
git checkout main
git pull origin main
# 3. Clean up local and remote refs (PARALLEL - run both simultaneously)
git branch -D <branch-name> # Delete local branch (-D required for squash merges)
git fetch --prune # Prune stale remote-tracking references
# 4. Verify remote branch was deleted
git branch -r | grep <branch-name> || echo "Remote branch deleted"
# 5. Update session purpose to indicate completion
# First, read the current purpose
cat .claude-metadata.json | jq -r '.purpose'
# Then update with completion prefix
./scripts/claude-instance purpose "COMPLETED: <previous-purpose>"
Note: Read the current purpose from .claude-metadata.json first, then replace
<previous-purpose> in the command with the actual value.
This marks the session as having completed its primary objective.
If remote branch still exists after verified merge: STOP.
Why cleanup immediately:
git merge to mainIf you think any of these, stop and follow the process:
| Thought | Reality |
|---|---|
| "PR title is what matters" | Description is permanent record. Both must be accurate. |
| "Description can be updated later" | Can't edit after merge. Do it now. |
| "Production urgency" | 5 min now saves hours debugging later. |
| "It's probably fine" | Run the commands. Takes 30 seconds. |
| "I'll clean up later" | You won't. Cleanup now. |