Local rebase-merge workflow for pull requests with linear git history and signed commits. Rebases PR onto main and pushes to origin/main.
Merges pull requests via local rebase to maintain linear history with signed commits. Triggered when a PR is approved with passing CI and all reviews resolved, it validates merge-readiness, rebases onto main, and pushes to auto-close the PR.
/plugin marketplace add JacobPEvans/claude-code-plugins/plugin install git-rebase-workflow@jacobpevans-cc-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Local rebase workflow for merging pull requests that maintains linear history with signed commits by rebasing PR branches onto main and pushing directly to origin/main (auto-closing the pull request).
GitHub's gh pr merge command does not sign commits, making it incompatible with repositories requiring commit signatures.
This workflow uses local git operations to preserve commit signing throughout the entire merge process.
Use this workflow when:
Do NOT use when:
gh pr merge)This is the canonical source of truth for pull request merge-readiness validation.
A pull request is READY TO MERGE when ALL of:
state == "OPEN" - Pull request is openmergeable == "MERGEABLE" - No merge conflicts with base branchstatusCheckRollup.state == "SUCCESS" - All CI checks pass on the pull requestreviewThreads have isResolved == true - All pull request review conversations resolvedreviewDecision == "APPROVED" or null - Pull request approved or review not requiredA pull request is BLOCKED when ANY of:
mergeable == "CONFLICTING" → "pull request has merge conflicts"statusCheckRollup.state != "SUCCESS" → "pull request CI failing: {checks}"reviewDecision == "CHANGES_REQUESTED" → "pull request reviewer requested changes"# Get current branch
BRANCH=$(git branch --show-current)
# Get pull request number for current branch
PR_NUMBER=$(gh pr view --json number --jq '.number')
If no pull request exists: ABORT with message "No pull request found for branch. Create a pull request first: gh pr create"
# Get owner and repo name
OWNER=$(gh repo view --json owner --jq '.owner.login')
REPO=$(gh repo view --json name --jq '.name')
Use the GitHub GraphQL Skill patterns:
<!-- markdownlint-disable-next-line MD013 -->
gh api graphql --raw-field 'query=query { repository(owner: "'"$OWNER"'", name: "'"$REPO"'") { pullRequest(number: '"$PR_NUMBER"') { state mergeable statusCheckRollup { state } reviewDecision reviewThreads(last: 100) { nodes { isResolved } } } } }'
Validation Requirements (ALL must pass):
| Field | Required Value | Abort Message |
|---|---|---|
state | OPEN | "PR is not open (state: {state})" |
mergeable | MERGEABLE | "PR has merge conflicts. Resolve before rebasing." |
statusCheckRollup.state | SUCCESS | "CI checks have not passed. Wait for green CI." |
reviewDecision | APPROVED or null | "PR requires approval. Get review first." |
All reviewThreads.nodes[].isResolved | true | "Unresolved review threads. Resolve all conversations." |
<!-- markdownlint-disable-next-line MD013 -->
gh api graphql --raw-field 'query=query { repository(owner: "'"$OWNER"'", name: "'"$REPO"'") { pullRequest(number: '"$PR_NUMBER"') { reviewThreads(last: 100) { nodes { isResolved } } } } }' | jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'
If count > 0: ABORT with "X unresolved review threads remain. Use /resolve-pr-review-thread first."
From Worktrees structure:
# Get repo name from remote URL
REPO_NAME=$(basename -s .git $(git config --get remote.origin.url))
MAIN_WORKTREE="$HOME/git/$REPO_NAME/main"
# Verify it exists
if [ ! -d "$MAIN_WORKTREE" ]; then
echo "Main worktree not found at $MAIN_WORKTREE"
exit 1
fi
Pattern from Sync Main lines 68-79:
# Use subshell to update main worktree
(
cd "$MAIN_WORKTREE"
git fetch origin main
git pull origin main
echo "Main worktree updated. Latest commit:"
git log -1 --oneline
)
MAIN_SHA=$(cd "$MAIN_WORKTREE" && git rev-parse --short HEAD)
echo "Local main now at: $MAIN_SHA"
git rebase main
Three possible outcomes:
If conflicts occur, list them:
# List conflicted files
git diff --name-only --diff-filter=U
For each conflicted file, apply intelligent resolution from Merge Conflict Resolution:
| Scenario | Resolution |
|---|---|
| Changes are additive | Keep BOTH changes |
| Changes modify same logic | Combine the intent of both |
| One is a bug fix | Always include the fix |
| One is a refactor | Apply refactor, then add the other change |
| Truly incompatible | Mark for manual resolution |
Resolution process:
# For each conflicted file:
# 1. Read the file to understand both sides
# 2. Edit to resolve intelligently
# 3. Stage the resolved file
git add <resolved-file>
# After all conflicts resolved
git rebase --continue
If conflicts are too complex:
git rebase --abort
ABORT with:
Rebase conflicts require manual resolution.
To resolve:
1. Run: git rebase main
2. Review each conflict and resolve intelligently
3. Stage resolved files: git add <file>
4. Continue: git rebase --continue
5. Try /rebase-merge again
# Check for ongoing rebase
if [ -d "$(git rev-parse --git-dir)/rebase-merge" ] || [ -d "$(git rev-parse --git-dir)/rebase-apply" ]; then
echo "Rebase still in progress"
exit 1
fi
# Verify branch is ahead of main
COMMITS_AHEAD=$(git log main..HEAD --oneline | wc -l)
echo "Branch is $COMMITS_AHEAD commits ahead of main"
cd "$MAIN_WORKTREE"
# Check if feature branch is directly ahead of main
git merge-base --is-ancestor main "$BRANCH"
if [ $? -ne 0 ]; then
echo "Cannot fast-forward: main has diverged"
exit 1
fi
git merge --ff-only "$BRANCH"
If fast-forward fails, ABORT with:
Cannot fast-forward merge. Main has diverged since rebase.
This usually means:
1. Someone pushed to main during your rebase
2. Run: git fetch origin main
3. Return to your worktree and run: git rebase origin/main
4. Try /rebase-merge again
git log -3 --oneline
echo "Main now includes: $(git log -1 --format='%s')"
git push origin main
This automatically closes the pull request because the PR's commits (with signatures) are now on main.
Note on Commit Signing: All commits retain their signatures through the rebase process.
This is critical for repositories with signing requirements and is why we use this local workflow instead of gh pr merge.
git fetch origin main
LOCAL=$(git rev-parse main)
REMOTE=$(git rev-parse origin/main)
if [ "$LOCAL" = "$REMOTE" ]; then
echo "Push successful. Origin/main updated."
else
echo "Push failed. Local and remote differ."
exit 1
fi
PR_STATE=$(gh pr view "$PR_NUMBER" --json state --jq '.state')
echo "Pull request state: $PR_STATE"
Expected: MERGED (GitHub detects commits now on main and auto-closes the pull request)
# Get back to the feature worktree before deletion
SAFE_BRANCH=$(printf '%s' "$BRANCH" | tr -c 'A-Za-z0-9._-/' '_')
FEATURE_WORKTREE="$HOME/git/$REPO_NAME/$SAFE_BRANCH"
From main worktree:
git branch -d "$BRANCH"
If fails (not fully merged):
# Force delete only if PR is verified merged
if [ "$PR_STATE" = "MERGED" ]; then
git branch -D "$BRANCH"
fi
git push origin --delete "$BRANCH" 2>/dev/null || echo "Remote branch already deleted"
Pattern from Sync Main lines 183-188:
if [ -d "$FEATURE_WORKTREE" ]; then
git worktree remove "$FEATURE_WORKTREE"
echo "Removed worktree: $FEATURE_WORKTREE"
fi
git worktree prune
git status
git log -5 --oneline origin/main
Detection: gh pr view returns error
Action: ABORT with "No pull request found for current branch. Create a pull request first: gh pr create"
Detection: mergeable == CONFLICTING
Action: ABORT with "Pull request has conflicts with main. Resolve conflicts in the PR first using /sync-main"
Detection: statusCheckRollup.state == PENDING
Action: ABORT with "Pull request CI checks still running. Wait for completion before merging."
Detection: statusCheckRollup.state == FAILURE
Action: ABORT with "Pull request CI checks are failing. Fix CI issues first using /fix-pr-ci"
Detection: reviewDecision == CHANGES_REQUESTED
Action: ABORT with "Pull request reviewer requested changes. Address feedback first."
Detection: Any reviewThreads[].isResolved == false
Action: ABORT with "Pull request has unresolved review threads. Use /resolve-pr-review-thread first."
Detection: state == MERGED
Action: Skip gracefully with "Pull request already merged. Cleaning up local and remote branches..."
Then proceed to Phase 6 cleanup only.
Detection: git merge --ff-only fails
Action: ABORT with instructions (see Phase 4.3)
Detection: git worktree remove fails
Action: Warn but continue:
Warning: Could not remove worktree (may be in use).
Manual cleanup required: git worktree remove <path>
Detection: Main worktree directory doesn't exist
Action: ABORT with:
Main worktree not found at ~/git/<repo>/main
This repository may not be using worktree structure.
See /init-worktree to set up proper worktree structure.
## Rebase Merge Complete
PR: #<number> - <title>
Branch: <branch-name>
Method: Local rebase + fast-forward push
### Actions Taken
1. ✅ Validated PR: OPEN, MERGEABLE, CI SUCCESS, APPROVED
2. ✅ Synced main: <old-sha> → <new-sha>
3. ✅ Rebased branch: <commits> commit(s)
4. ✅ Fast-forward merged to main
5. ✅ Pushed to origin/main
6. ✅ PR auto-closed by GitHub
### Cleanup
- Deleted local branch: <branch>
- Deleted remote branch: origin/<branch>
- Removed worktree: <path>
### Result
Main branch now at: <commit-sha>
Linear history preserved ✨
| Wrong | Right |
|---|---|
git push --force origin main | Never force push to main |
| Merge without checking CI | Always verify all checks pass |
| Skip thread resolution check | All threads must be marked resolved |
| Rebase when others are pushing to branch | Coordinate with team first |
| Delete branch before verifying merge | Confirm PR state is MERGED |
Use git checkout --theirs blindly | Analyze and combine both sides |
/rebase-pr - Primary consumer/ready-player-one - Uses merge-readiness criteria/git-refresh - References merge-readiness criteriaApplies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.