| name | merge-pr |
| description | Safely merges GitHub pull requests using gh CLI. Use when the user wants to merge a PR, merge a pull request, or complete code review. |
| allowed-tools | ["Bash","Read","Grep"] |
Merge PR Skill
Assists with safely merging GitHub pull requests using the gh CLI, following best practices for code review, CI checks, and merge strategies.
IMPORTANT: When using this skill, announce to the user: "Using merge-pr skill to merge a pull request safely."
Instructions
1. Pre-Merge Checks
ALWAYS verify the following before merging:
gh pr view [PR_NUMBER]
gh pr checks [PR_NUMBER]
gh pr diff [PR_NUMBER]
Required conditions before merging:
- ✅ All required CI checks must pass
- ✅ Required approvals must be met (check branch protection rules)
- ✅ No unresolved review comments or change requests
- ⚠️ Confirm you have permission to merge
If checks fail:
- Wait for CI to complete
- Address review feedback
- Fix failing tests
- Re-run checks if needed:
gh pr checks --watch [PR_NUMBER]
2. Merge Strategy Selection
Default: Merge Commit (--merge)
- Preserves all commits from the PR branch
- Creates a merge commit
- Maintains complete history
- ALWAYS specify merge commit subject in this format:
:inbox_tray: Merge pull request #[PR_NUMBER] from [BRANCH_NAME]
BRANCH_NAME=$(gh pr view [PR_NUMBER] --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge [PR_NUMBER] --merge --subject ":inbox_tray: Merge pull request #[PR_NUMBER] from $BRANCH_NAME"
Alternative strategies (use only when appropriate):
Squash Merge (--squash)
- Combines all commits into a single commit
- Use when: PR has many small/WIP commits that should be consolidated
gh pr merge [PR_NUMBER] --squash
Rebase Merge (--rebase)
- Replays commits from PR branch onto base branch
- Use when: Small PRs with clean commits, want linear history without merge commit
gh pr merge [PR_NUMBER] --rebase
3. Branch Deletion
Branch deletion is handled by GitHub repository settings:
- Repository settings → "Automatically delete head branches"
- If enabled, branches are deleted automatically after merge
- If disabled, branches remain for manual cleanup
- Do NOT use
--delete-branch flag - respect the repository configuration
4. Post-Merge Local Update
After merging a PR, ALWAYS update your local default branch:
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
git branch --merged | grep -v "\*" | grep -v "$DEFAULT_BRANCH" | xargs -n 1 git branch -d
Alternative (if you know the default branch name):
git checkout main && git pull
git checkout master && git pull
5. Complete Merge Workflow
Follow this sequence:
gh pr view [PR_NUMBER]
gh pr checks [PR_NUMBER]
BRANCH_NAME=$(gh pr view [PR_NUMBER] --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge [PR_NUMBER] --merge --subject ":inbox_tray: Merge pull request #[PR_NUMBER] from $BRANCH_NAME"
gh pr view [PR_NUMBER]
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
git branch --merged | grep -v "\*" | grep -v "$DEFAULT_BRANCH" | xargs -n 1 git branch -d
6. Safety Guidelines
NEVER merge if:
- ❌ CI checks are failing
- ❌ There are unresolved change requests from reviewers
- ❌ You don't have proper permissions
- ❌ The PR targets the wrong base branch
- ❌ Required approvals are missing
ALWAYS:
- ✅ Read PR description and understand what's being merged
- ✅ Verify CI passes completely
- ✅ Check that required reviews are approved
- ✅ Use
--merge (default strategy) to preserve commit history
- ✅ Specify merge commit subject as
:inbox_tray: Merge pull request #[PR_NUMBER] from [BRANCH_NAME]
- ✅ Update local default branch after merging
- ✅ Let GitHub repository settings handle branch deletion
7. Common gh pr merge Options
BRANCH_NAME=$(gh pr view [PR_NUMBER] --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge [PR_NUMBER] --merge --subject ":inbox_tray: Merge pull request #[PR_NUMBER] from $BRANCH_NAME"
gh pr merge [PR_NUMBER] --squash
gh pr merge [PR_NUMBER] --rebase
BRANCH_NAME=$(gh pr view [PR_NUMBER] --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge [PR_NUMBER] --auto --merge --subject ":inbox_tray: Merge pull request #[PR_NUMBER] from $BRANCH_NAME"
BRANCH_NAME=$(gh pr view --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge --merge --subject ":inbox_tray: Merge pull request #[PR_NUMBER] from $BRANCH_NAME"
gh pr merge [PR_NUMBER] --disable-auto
8. Working with the Current Branch
If you're on a branch with an open PR:
PR_NUMBER=$(gh pr view --json number -q .number)
BRANCH_NAME=$(gh pr view --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge --merge --subject ":inbox_tray: Merge pull request #$PR_NUMBER from $BRANCH_NAME"
gh pr status
gh pr view
Examples
Example 1: Standard Merge with Merge Commit (Default)
gh pr view 42
gh pr checks 42
BRANCH_NAME=$(gh pr view 42 --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge 42 --merge --subject ":inbox_tray: Merge pull request #42 from $BRANCH_NAME"
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
Example 2: Complete Workflow with Cleanup
gh pr view 42
gh pr checks 42
BRANCH_NAME=$(gh pr view 42 --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge 42 --merge --subject ":inbox_tray: Merge pull request #42 from $BRANCH_NAME"
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
git branch --merged | grep -v "\*" | grep -v "$DEFAULT_BRANCH" | xargs -n 1 git branch -d
Example 3: Auto-merge with Local Update
BRANCH_NAME=$(gh pr view 99 --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge 99 --auto --merge --subject ":inbox_tray: Merge pull request #99 from $BRANCH_NAME"
gh pr view 99
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
Example 4: Merge Current Branch
gh pr view
PR_NUMBER=$(gh pr view --json number -q .number)
BRANCH_NAME=$(gh pr view --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge --merge --subject ":inbox_tray: Merge pull request #$PR_NUMBER from $BRANCH_NAME"
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
Common Pitfalls to Avoid
- Don't merge with failing checks: Always verify
gh pr checks passes
- Don't specify branch deletion: Let GitHub settings handle it
- Don't merge without reviews: Check that required approvals are present
- Don't merge to wrong branch: Verify base branch in
gh pr view
- Don't forget to update local: Always pull the default branch after merging
- Don't hardcode branch name: Use
gh repo view --json defaultBranchRef to get the correct default branch
- Don't use squash by default: Use
--merge to preserve commit history
- Don't forget merge commit subject: Always use
:inbox_tray: Merge pull request #[PR_NUMBER] from [BRANCH_NAME] format
Error Recovery
If merge fails due to conflicts:
gh pr checkout [PR_NUMBER]
git fetch origin
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git merge "origin/$DEFAULT_BRANCH"
git push
BRANCH_NAME=$(gh pr view [PR_NUMBER] --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge [PR_NUMBER] --merge --subject ":inbox_tray: Merge pull request #[PR_NUMBER] from $BRANCH_NAME"
If accidentally merged wrong PR:
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
git log
git revert -m 1 [MERGE_COMMIT_HASH]
git push
If local update fails:
git branch
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git stash
git pull
git stash pop
Advanced Usage
Check repository default branch:
gh repo view --json defaultBranchRef -q .defaultBranchRef.name
gh repo view --json defaultBranchRef
Check if PR is ready to merge:
gh pr view [PR_NUMBER] --json statusCheckRollup,reviewDecision
gh pr checks [PR_NUMBER] --watch
Merge multiple PRs:
for pr in 42 43 44; do
if gh pr checks $pr; then
BRANCH_NAME=$(gh pr view $pr --json headRepositoryOwner,headRefName -q '.headRepositoryOwner.login + "/" + .headRefName')
gh pr merge $pr --merge --subject ":inbox_tray: Merge pull request #$pr from $BRANCH_NAME"
fi
done
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
git checkout "$DEFAULT_BRANCH"
git pull
Query mergeable state:
gh pr view [PR_NUMBER] --json mergeable,mergeStateStatus
Project-Specific Conventions
Always check if the project has specific merge requirements:
- Read
CONTRIBUTING.md for merge strategy preferences
- Check branch protection rules on GitHub
- Follow team conventions for commit messages
- Respect required reviewers and approvals
- Default to
--merge unless project specifies otherwise
- Branch deletion is controlled by repository settings, not by this skill
- Use
gh repo view --json defaultBranchRef to detect the default branch dynamically
- Merge commit subject format: Always use
:inbox_tray: Merge pull request #[PR_NUMBER] from [BRANCH_NAME]