pr-sync
PR Sync Skill
Sync local changes to GitHub in a single command. Detects current state (main vs feature branch, staged vs unstaged changes, existing PRs), then executes the minimum steps needed: branch, commit, push, and create PR. Execute only the steps needed for the current state -- do not add extra commits, rebase, or reorganize history beyond what is required to sync.
Usage
/pr-sync # Auto-detect everything
/pr-sync feature/new-auth # Specify branch name
/pr-sync fix/bug-123 "Fix login" # Specify branch and PR title
Instructions
Step 0: Read CLAUDE.md and Classify Repo
Read and follow the repository CLAUDE.md before any git operations, because repo-specific branch conventions, commit formats, or CI requirements override defaults in this skill.
Then determine repo type:
REPO_TYPE=$(python3 ~/.claude/scripts/classify-repo.py --type-only)
Protected-org repos: Every subsequent step (commit, push, PR creation) requires explicit user confirmation. Present the proposed action, show what will happen, and wait for approval before executing. Never auto-execute, because protected-org repos have CI gates and review policies that assume human oversight at each stage.
Personal repos: Run /pr-review comprehensive review before creating the PR. Auto-execute steps normally.
Step 1: Detect Current State
Always detect state before taking any action, because skipping detection risks creating nested branches, committing to the wrong branch, or duplicating work already done.
# Get current branch
CURRENT_BRANCH=$(git branch --show-current)
# Detect main branch name
MAIN_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "master")
# Check for uncommitted changes
HAS_CHANGES=$(git status --porcelain)
# Check for unpushed commits (include these in the push so nothing is left behind)
UNPUSHED=$(git log origin/$CURRENT_BRANCH..$CURRENT_BRANCH --oneline 2>/dev/null)
# Determine if on main/master
ON_MAIN=false
if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]]; then
ON_MAIN=true
fi
If the branch is behind remote, warn the user before pushing so they can pull or rebase first and avoid a rejected push.
Step 2: Create Branch (if on main)
Never commit directly to main/master -- always create a feature branch first, because direct main commits skip code review, make rollback harder, and can break CI for everyone.
If on main/master with changes, create a feature branch. If no branch name was provided, generate one from the changes or commit message.
Branch naming conventions:
| Change Type | Prefix | Example |
|---|---|---|
| New feature | feature/ |
feature/add-auth |
| Bug fix | fix/ |
fix/login-error |
| Documentation | docs/ |
docs/update-readme |
| Refactoring | refactor/ |
refactor/cleanup-utils |
| Chore/maintenance | chore/ |
chore/update-deps |
git checkout -b "$BRANCH_NAME"
If already on a feature branch, skip this step.
Step 3: Stage and Commit
Stage files selectively by name rather than using git add -A, because blind staging catches unintended files -- build artifacts, .env files, editor configs, large binaries -- that pollute the repository and may leak secrets. Review git status, stage specific files, and verify with git diff --cached before committing.
Never commit .env, credentials, secrets, or API keys. Block these files and warn the user if they appear in the staging area.
All commit messages use conventional commit format (type(scope): description).
# Stage specific files (not git add -A)
git add path/to/changed/files
# Create commit with conventional format
git commit -m "type(scope): description"
If no uncommitted changes exist, skip to Step 4.
Protected-org repos: Before executing the commit, present the proposed commit message and list of files to the user. Wait for explicit approval before committing.
Step 4: Push to Remote
All pushes use standard git push, never --force, because force pushing destroys remote history and teammates lose work. If push is rejected due to the branch being behind remote, pull with rebase and resolve conflicts rather than forcing.
# Push with upstream tracking (CLAUDE_GATE_BYPASS=1 bypasses the git-submission-gate hook)
CLAUDE_GATE_BYPASS=1 git push -u origin "$CURRENT_BRANCH"
If the user requested a rebase before push, run git pull --rebase origin $MAIN_BRANCH first, but this is off by default.
Protected-org repos: Before executing the push, present the branch name, remote, and commits that will be pushed. Wait for explicit approval before pushing.
Step 4a: ADR Decision Coverage (conditional -- ADR-094)
Skip if: No .adr-session.json exists in the working directory.
When an active ADR session exists, run the coverage check before the review loop:
python3 scripts/adr-decision-coverage.py --adr <active-adr-path> --diff-base main --human
If verdict is PARTIAL or FAIL, display uncovered decision points and ask whether to proceed or address gaps first. This runs once before the review loop, not on every iteration.
Step 4b: Review-Fix Loop (personal repos only)
Skip if: REPO_TYPE == "protected-org" (protected-org repos use their own review gates).
Iteratively review and fix issues before creating the PR. Up to 3 iterations of: /pr-review -> fix -> amend -> push.
Never modify commits already on the remote except the tip commit just pushed by this workflow. The review-fix loop amends only the tip commit it just created, before any external review, and uses --force-with-lease (not --force) because lease-checking confirms no one else has pushed to the branch in the meantime.
Loop (max 3 iterations):
- Run
/pr-reviewcomprehensive review - If clean -> exit loop, proceed to Step 5
- Fix all reported issues
git add [fixes] && git commit --amend --no-edit && CLAUDE_GATE_BYPASS=1 git push --force-with-lease- Report iteration:
REVIEW-FIX [N/3]: X found, Y fixed, Z remaining
After 3 iterations, proceed to Step 5 with any remaining issues documented in the PR body.
Step 5: Create or Update PR
Generate the PR title from the branch name or first commit when not provided by the user. Never create a PR with an empty description, because reviewers need context to understand the changes and a missing test plan signals incomplete work.
# Check if PR already exists for this branch
EXISTING_PR=$(gh pr list --head "$CURRENT_BRANCH" --json number --jq '.[0].number' 2>/dev/null)
if [[ -z "$EXISTING_PR" ]]; then
# Create new PR
CLAUDE_GATE_BYPASS=1 gh pr create --title "$PR_TITLE" --body "$(cat <<'EOF'
## Summary
[Description of changes]
## Test Plan
- [ ] Tested locally
- [ ] Tests pass
EOF
)"
else
# PR exists, just pushed updates
echo "PR #$EXISTING_PR updated with new commits"
gh pr view "$EXISTING_PR" --web
fi
If the user requested a draft PR, add --draft to gh pr create. If auto-assign reviewers was requested, assign based on CODEOWNERS.
Always show the PR URL after creation for easy access.
Protected-org repos: Before executing PR creation, present the PR title, body, and target branch. Wait for explicit approval. Do not run the review-fix loop -- protected-org repos rely on their own CI gates and human reviewers.
Step 6: Post-Merge ADR Status Update (conditional -- ADR-095)
Skip if: No .adr-session.json exists, or the PR was only created (not merged).
After a PR is merged (confirmed via gh pr view --json state), update the ADR lifecycle:
# 1. Read active ADR path
ADR_PATH=$(python3 -c "import json; print(json.load(open('.adr-session.json'))['adr_path'])")
# 2. Update status to Accepted
sed -i 's/^## Status$/&/' "$ADR_PATH" # (use Edit tool in practice)
# 3. Move to completed/
mv "$ADR_PATH" adr/completed/
# 4. Clear session
rm .adr-session.json
Report: ADR updated: {name} -> Accepted, moved to completed/
This is local-only (ADR files are gitignored). No branch or PR needed.
Decision Tree
/pr-sync invoked
|
v
Read CLAUDE.md + Classify repo (Step 0)
|
v
Has changes?
/ \
YES NO
| |
v v
On main? PR exists?
/ \ / \
YES NO YES NO
| | | |
v v v v
Create Stage Show Create
branch commit link PR
| |
v v
Stage & commit
|
v
protected-org? ──YES──> Confirm commit msg with user
| |
NO v
| Confirm push with user
v |
Push to remote <──────┘
|
v
protected-org? ──YES──> Confirm PR creation with user
| |
NO v
| Create PR, STOP (no merge)
v
┌─> Run /pr-review (iteration N/3)
| |
| v
| Issues found?
| / \
| YES NO ──────> Create PR
| |
| v
| Fix issues
| |
| v
| Amend commit, push
| |
| v
| N < 3? ──YES──┐
| | |
| NO |
| | |
| v |
| Create PR |
| (note remaining)|
└─────────────────┘
Output Format
Personal repos:
PR SYNC COMPLETE
Status: [on main -> created branch | on feature branch]
Changes: [N files modified]
Review: /pr-review [N iterations] — [X issues found, Y fixed]
Actions:
- Created branch: feature/your-feature (if from main)
- Staged N files
- Committed: "your commit message"
- Pushed to origin/feature/your-feature
- Review-fix loop: [N/3 iterations]
- Iteration 1: [X found, Y fixed]
- Iteration 2: [X found, Y fixed] (if needed)
- Iteration 3: [X found, Y fixed] (if needed)
- Created PR #123: "PR Title"
https://github.com/owner/repo/pull/123
Protected-org repos:
PR SYNC COMPLETE (protected-org repo — human-gated)
Status: [on feature branch]
Changes: [N files modified]
Actions (each confirmed by user):
- Committed: "your commit message" (user confirmed)
- Pushed to origin/feature/your-feature (user confirmed)
- Created PR #123: "PR Title" (user confirmed)
https://github.com/your-org/your-repo/pull/123
Next steps: Review and merge handled by org CI gates and human reviewers.
Error Handling
Error: "Push rejected - branch behind remote"
Cause: Remote branch has commits not present locally (teammate pushed, or previous rebase). Solution:
- Run
git pull --rebase origin $CURRENT_BRANCH - Resolve any conflicts if they arise
- Retry the push
- If conflicts are complex, inform the user and show the conflicting files
Error: "gh: not authenticated"
Cause: GitHub CLI is not authenticated or token expired. Solution:
- Run
gh auth statusto confirm - Instruct user to run
gh auth login - Do not proceed with PR creation until auth is confirmed
Error: "No changes to commit"
Cause: All changes are already committed, or working tree is clean. Solution:
- Check for unpushed commits with
git log origin/$BRANCH..$BRANCH - If unpushed commits exist, skip to push step
- If no unpushed commits, check if PR exists and show its status
- If nothing to do, report clean state to user
Error: "Branch name already exists"
Cause: A branch with the generated name already exists locally or on remote. Solution:
- Check if user is already on that branch (
git branch --show-current) - If different branch, append a suffix (e.g.,
-v2) or ask user for alternative name - Never silently overwrite an existing branch
Error: "Cannot delete branch used by worktree"
Cause: A git worktree references the branch, blocking deletion during PR merge or cleanup. Solution:
- Run
git worktree listto identify the worktree using the branch - Run
git worktree remove <path>to detach the worktree - Retry the branch deletion or PR merge with
--delete-branch - This commonly happens when worktree agents (
isolation: "worktree") created the branch
Error: "git push says up-to-date but changes are missing on remote"
Cause: git push origin master reports "up-to-date" when HEAD is on a different branch. Git pushes the named remote ref, not the current branch, so feature branch commits are never pushed.
Solution:
- Always push the current branch:
git push -u origin $(git branch --show-current) - Never hardcode branch names in push commands
- Verify after push:
git log origin/$(git branch --show-current)..HEADshould show 0 commits Graduated from learning.db -- multi-agent-coordination/worktree-push-from-wrong-branch
References
/pr-review-- Comprehensive PR review (used in the review-fix loop)/pr-cleanup-- Post-merge branch cleanupscripts/classify-repo.py-- Repo classification for workflow gatingscripts/adr-decision-coverage.py-- ADR decision coverage checker
More from notque/claude-code-toolkit
generate-claudemd
Generate project-specific CLAUDE.md from repo analysis.
12fish-shell-config
Fish shell configuration and PATH management.
12pptx-generator
PPTX presentation generation with visual QA: slides, pitch decks.
12codebase-overview
Systematic codebase exploration and architecture mapping.
10image-to-video
FFmpeg-based video creation from image and audio.
9data-analysis
Decision-first data analysis with statistical rigor gates.
9