Creates GitHub Pull Requests with existing PR detection, branch pushing, and intelligent title/body generation. Use when user requests to create pull request, open PR, update PR, push for review, ready for review, send for review, get this reviewed, make a PR, share code, request review, create draft PR, submit for review, run /create-pr command, or mentions "PR", "pull request", "merge request", "code review", "GitHub PR", or "draft".
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
EXAMPLES.mdTROUBLESHOOTING.mdWORKFLOW.mdYOU MUST NEVER add Claude Code attribution to pull requests.
Pull requests are public code review documents and must remain clean and professional.
Execute GitHub Pull Request workflows with automatic repository detection, branch management, and intelligent PR content generation.
This skill is invoked when:
/create-pr or /git:create-pr commandThis skill handles the complete PR workflow:
Parse arguments from user input:
<scope>: Direct PR for specific repository (root, submodule-name)--draft: Create as draft PR--base <branch>: Target branch (default: main)<scope> --draft, root --base staging, etc.GitHub CLI Required: Must have gh installed and authenticated
# Install GitHub CLI (if not installed)
# macOS: brew install gh
# Linux: See https://cli.github.com/
# Authenticate
gh auth login
Extract scope, draft flag, and base branch from user input:
# Parse arguments
SCOPE=""
DRAFT_FLAG=""
BASE_BRANCH="main"
# Example parsing:
# "root --draft" → SCOPE="root", DRAFT_FLAG="--draft", BASE_BRANCH="main"
# "--base staging" → SCOPE="", DRAFT_FLAG="", BASE_BRANCH="staging"
# "my-service --draft --base develop" → SCOPE="my-service", DRAFT_FLAG="--draft", BASE_BRANCH="develop"
Find monorepo root and determine current repository:
# Find monorepo root (handles submodules)
if SUPERPROJECT=$(git rev-parse --show-superproject-working-tree 2>/dev/null) && [ -n "$SUPERPROJECT" ]; then
# We're in a submodule
MONOREPO_ROOT="$SUPERPROJECT"
else
# We're in root or standalone repo
MONOREPO_ROOT=$(git rev-parse --show-toplevel)
fi
# Get current working directory
CURRENT_DIR=$(pwd)
# Determine repository context
if [ -n "$SCOPE" ]; then
# User specified scope
if [ "$SCOPE" = "root" ]; then
REPO_PATH="$MONOREPO_ROOT"
else
REPO_PATH="$MONOREPO_ROOT/$SCOPE"
fi
else
# Auto-detect from current directory
# If in submodule, use submodule path
# If in root, use root path
if [[ "$CURRENT_DIR" == "$MONOREPO_ROOT" ]]; then
REPO_PATH="$MONOREPO_ROOT"
else
# Find which submodule we're in
REPO_PATH=$(git -C "$CURRENT_DIR" rev-parse --show-toplevel)
fi
fi
# Validate repository
if [ ! -d "$REPO_PATH/.git" ]; then
echo "❌ Error: Not a valid git repository: $REPO_PATH" >&2
exit 1
fi
Check current branch and uncommitted changes:
# Change to repository directory
cd "$REPO_PATH"
# Get current branch
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# Check if on protected branch
if [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "master" ]; then
echo "❌ Cannot create PR from protected branch: $CURRENT_BRANCH" >&2
echo "" >&2
echo "Please create a feature branch first:" >&2
echo " git checkout -b feature/your-feature-name" >&2
echo "" >&2
exit 1
fi
# Check for uncommitted changes
UNCOMMITTED=$(git status --porcelain)
if [ -n "$UNCOMMITTED" ]; then
echo "❌ Error: You have uncommitted changes" >&2
echo "" >&2
echo "Please commit or stash your changes before creating a PR:" >&2
git status --short
echo "" >&2
exit 1
fi
# Check if branch has commits ahead of base
COMMITS_AHEAD=$(git rev-list --count "$BASE_BRANCH..HEAD" 2>/dev/null || echo "0")
if [ "$COMMITS_AHEAD" = "0" ]; then
echo "❌ Error: No commits to create PR from" >&2
echo "Current branch '$CURRENT_BRANCH' has no commits ahead of '$BASE_BRANCH'" >&2
exit 1
fi
echo "ℹ️ Branch: $CURRENT_BRANCH ($COMMITS_AHEAD commits ahead of $BASE_BRANCH)"
Ensure branch exists on remote:
# Check if branch exists on remote
REMOTE_BRANCH=$(git ls-remote --heads origin "$CURRENT_BRANCH" 2>/dev/null)
if [ -z "$REMOTE_BRANCH" ]; then
echo "ℹ️ Branch not on remote, pushing..."
git push -u origin "$CURRENT_BRANCH" || {
echo "❌ Failed to push branch to remote" >&2
exit 1
}
echo "✅ Branch pushed to origin/$CURRENT_BRANCH"
else
# Check if local is behind remote
LOCAL_HASH=$(git rev-parse HEAD)
REMOTE_HASH=$(git rev-parse "origin/$CURRENT_BRANCH" 2>/dev/null || echo "")
if [ "$LOCAL_HASH" != "$REMOTE_HASH" ]; then
echo "ℹ️ Local branch differs from remote, pushing..."
git push origin "$CURRENT_BRANCH" || {
echo "❌ Failed to push branch to remote" >&2
exit 1
}
echo "✅ Branch updated on remote"
else
echo "ℹ️ Branch already up to date on remote"
fi
fi
Detect if PR already exists for this branch:
# Check for existing PR using GitHub CLI
EXISTING_PR=$(gh pr view "$CURRENT_BRANCH" --json number,title,url 2>/dev/null || echo "")
if [ -n "$EXISTING_PR" ]; then
# PR exists - extract info
PR_NUMBER=$(echo "$EXISTING_PR" | jq -r '.number')
PR_TITLE=$(echo "$EXISTING_PR" | jq -r '.title')
PR_URL=$(echo "$EXISTING_PR" | jq -r '.url')
echo ""
echo "ℹ️ Existing PR found:"
echo " #$PR_NUMBER: $PR_TITLE"
echo " $PR_URL"
echo ""
# Use AskUserQuestion to ask user what to do
# Options:
# 1. Update PR (regenerate title/body and update)
# 2. View PR in browser (open URL)
# 3. Cancel (do nothing)
# If user chooses "Update PR":
# - Generate new title and body (Steps 6-7)
# - Update PR using: gh pr edit "$PR_NUMBER" --title "..." --body "..."
# - Show success message
# If user chooses "View PR":
# - Open PR URL in browser: gh pr view --web
# If user chooses "Cancel":
# - Exit gracefully
fi
Analyze commits to create conventional PR title:
# Get all commits from base branch to current branch
COMMITS=$(git log "$BASE_BRANCH..HEAD" --oneline)
COMMIT_COUNT=$(echo "$COMMITS" | wc -l | tr -d ' ')
echo "ℹ️ Analyzing $COMMIT_COUNT commits..."
# Get the first commit message (most recent)
LATEST_COMMIT=$(git log -1 --pretty=%B)
# Detect commit type from latest commit or analyze all commits
# Try to extract type from conventional commit format
if echo "$LATEST_COMMIT" | grep -qE '^(feat|fix|docs|refactor|test|chore|perf|ci|build):'; then
# Extract type and description from conventional commit
COMMIT_TYPE=$(echo "$LATEST_COMMIT" | grep -oE '^[a-z]+' | head -1)
COMMIT_DESC=$(echo "$LATEST_COMMIT" | sed -E 's/^[a-z]+(\([^)]+\))?:\s*//')
else
# Analyze changes to determine type
ALL_COMMITS=$(git log "$BASE_BRANCH..HEAD" --pretty=%B)
if echo "$ALL_COMMITS" | grep -qi "fix\|bug"; then
COMMIT_TYPE="fix"
elif echo "$ALL_COMMITS" | grep -qi "feat\|feature\|add"; then
COMMIT_TYPE="feat"
elif echo "$ALL_COMMITS" | grep -qi "docs\|documentation"; then
COMMIT_TYPE="docs"
elif echo "$ALL_COMMITS" | grep -qi "refactor"; then
COMMIT_TYPE="refactor"
elif echo "$ALL_COMMITS" | grep -qi "test"; then
COMMIT_TYPE="test"
else
COMMIT_TYPE="feat"
fi
# Generate description from branch name or commit
COMMIT_DESC=$(echo "$LATEST_COMMIT" | head -1 | sed 's/^\s*//')
fi
# Generate PR title (capitalize first letter)
PR_TITLE="$COMMIT_TYPE: $COMMIT_DESC"
echo "ℹ️ Generated PR title: $PR_TITLE"
Create PR description with summary and test plan:
# Generate PR body with summary from commits
PR_BODY="## Summary
"
# Add commit summaries
if [ "$COMMIT_COUNT" -eq 1 ]; then
# Single commit - use full message
PR_BODY+="$LATEST_COMMIT
"
else
# Multiple commits - list them
PR_BODY+="This PR includes $COMMIT_COUNT commits:
"
while IFS= read -r commit; do
PR_BODY+="- $commit
"
done <<< "$COMMITS"
PR_BODY+="
"
fi
# Add test plan section
PR_BODY+="## Test Plan
- [ ] Code builds successfully
- [ ] Tests pass
- [ ] Manual testing completed
- [ ] Documentation updated (if needed)
## Changes
"
# List changed files
CHANGED_FILES=$(git diff --name-only "$BASE_BRANCH..HEAD")
while IFS= read -r file; do
PR_BODY+="- \`$file\`
"
done <<< "$CHANGED_FILES"
echo ""
echo "Generated PR description:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "$PR_BODY"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
Use GitHub CLI to create the PR:
# IMPORTANT: No Claude Code attribution in PR content
# Build gh pr create command
GH_CMD="gh pr create --title \"$PR_TITLE\" --body \"$PR_BODY\" --base \"$BASE_BRANCH\""
# Add draft flag if specified
if [ "$DRAFT_FLAG" = "--draft" ]; then
GH_CMD+=" --draft"
fi
# Execute PR creation
eval "$GH_CMD" || {
echo "❌ Failed to create PR" >&2
exit 1
}
# Get PR URL
PR_URL=$(gh pr view --json url -q '.url')
echo ""
echo "✅ Pull Request created successfully!"
echo ""
echo "PR URL: $PR_URL"
echo ""
echo "Next steps:"
echo " - Review PR in browser: gh pr view --web"
echo " - Check CI status: gh pr checks"
echo " - Request reviews: gh pr ready (if draft)"
echo ""
If updating an existing PR (user chose "Update" in Step 5):
# Update PR title and body
gh pr edit "$PR_NUMBER" --title "$PR_TITLE" --body "$PR_BODY" || {
echo "❌ Failed to update PR" >&2
exit 1
}
echo "✅ Pull Request #$PR_NUMBER updated successfully!"
echo "PR URL: $PR_URL"
The skill generates PR titles following conventional commit format:
| Detected Pattern | Type | Example Title |
|---|---|---|
| "feat:" in commits | feat | feat: add user authentication |
| "fix:" in commits | fix | fix: resolve login timeout issue |
| "docs:" in commits | docs | docs: update API documentation |
| "refactor:" in commits | refactor | refactor: optimize database queries |
| "test:" in commits | test | test: add integration tests |
| Mentions "bug", "fix" | fix | fix: correct calculation error |
| Mentions "feature", "add" | feat | feat: implement new feature |
| Default | feat | feat: [description from commits] |
GitHub CLI Required: Must have gh installed and authenticated
gh auth login
Branch Protection: Cannot create PR from main/master branch
Existing PRs: Automatically detects and offers to update existing PRs
Commit-Based Content: PR title and body generated from commit messages
Works Anywhere: Executes from any directory, resolves paths absolutely
Submodule Support: Can create PRs for both root repository and submodules
Clean PR Content: No Claude Code attribution in PR titles or descriptions
This skill uses the following gh commands:
# Check for existing PR
gh pr view <branch> --json number,title,url
# Create new PR
gh pr create --title "..." --body "..." --base <branch> [--draft]
# Update existing PR
gh pr edit <number> --title "..." --body "..."
# View PR in browser
gh pr view --web
# Check PR status
gh pr checks
For detailed information, see: