/git:upstream-pr
Submit clean, atomic PRs to upstream repositories from fork work.
When to Use This Skill
Use this skill when... Use /git:commit instead when...
Contributing changes back to the upstream repo Committing to your own fork/repo
Cherry-picking fork commits for upstream PR Creating a PR within the same repo
Fork's main has diverged from upstream Fork and upstream are in sync
Need a clean branch based on upstream/main Working on a branch already tracking upstream
Context
-
Current branch: !git branch --show-current
-
Git status: !git status --porcelain=v2 --branch
-
Remotes: !git remote -v
-
Has upstream: !git remote get-url upstream
-
Origin URL: !git remote get-url origin
-
Upstream URL: !git remote get-url upstream
-
Recent commits: !git log --oneline --max-count=20
-
Stash list: !git stash list
Parameters
Parse these from $ARGUMENTS :
Parameter Required Description
--commits sha1,sha2,...
No Comma-separated commit SHAs to cherry-pick (interactive selection if omitted)
--branch name
No Name for the upstream PR branch (auto-generated if omitted)
--upstream owner/repo
No Override upstream repo (detected from remote if omitted)
--draft
No Create PR as draft
--dry-run
No Show what would happen without making changes
Execution
Execute this fork-to-upstream PR workflow:
Step 1: Validate fork environment
-
Verify this is a git repository: git rev-parse --git-dir
-
Check if upstream remote exists (from context)
-
If no upstream remote:
-
Try to detect via gh repo view --json parent -q '.parent.nameWithOwner'
-
If found, add it: git remote add upstream https://github.com/<owner/repo>.git
-
If not found, ask user with AskUserQuestion for the upstream repo URL
-
Fetch upstream: git fetch upstream
-
Record the current branch name and check for uncommitted changes
-
If uncommitted changes exist, stash them: git stash push -m "upstream-pr: WIP before upstream PR"
Step 2: Assess fork state
Report the fork's divergence from upstream:
Fork status: Upstream: <upstream-repo> Behind upstream/main: N commits Ahead of upstream/main: M commits
If --dry-run is set, also show which commits would be selected and stop here.
Step 3: Select commits
If --commits provided:
-
Parse the comma-separated SHA list
-
Validate each SHA exists: git rev-parse --verify <sha>
-
Show summary of selected commits
If --commits not provided:
-
Show recent commits that are ahead of upstream/main: git log --oneline --format='%h %s (%cr)' upstream/main..HEAD
-
Use AskUserQuestion to let the user select which commits to include
-
Present commits as options with their subject lines
Step 4: Create clean branch from upstream/main
-
Generate branch name if --branch not provided:
-
Extract scope from first commit message (e.g., feat(auth): add OAuth -> feat/auth-add-oauth )
-
Fallback: upstream-pr/<date>
-
Create branch from upstream/main: git switch -c <branch-name> upstream/main
Step 5: Cherry-pick and squash
-
Cherry-pick each selected commit in order: git cherry-pick <sha1> <sha2> ...
-
If cherry-pick conflicts occur:
-
Report the conflict to the user
-
Reference git-conflicts for resolution
-
After resolution: git cherry-pick --continue
-
Squash all cherry-picked commits into one atomic commit: git reset --soft upstream/main git commit -m "<conventional commit message>"
-
Use AskUserQuestion to confirm or edit the commit message
-
Default message: derived from the cherry-picked commits
-
Format: conventional commit with scope
Step 6: Push to fork
git push -u origin <branch-name>
If --dry-run , show the command without executing.
Step 7: Create cross-fork PR
-
Determine the upstream repo (from --upstream or detected remote)
-
Determine the fork owner (from origin remote URL)
-
Create the PR: gh pr create
--repo <upstream-owner/upstream-repo>
--base main
--head <fork-owner>:<branch-name>
--title "<conventional commit title>"
--body "<PR description>"
Add --draft if the flag was provided.
- Report the PR URL to the user
Step 8: Restore working state
-
Switch back to the original branch: git switch <original-branch>
-
If changes were stashed in Step 1, pop them: git stash pop
-
Report completion summary: Upstream PR created: PR: <url> Branch: <branch-name> Commits: N cherry-picked, squashed into 1 Original branch restored: <branch>
Error Handling
Error Recovery
Cherry-pick conflict Show conflicted files, reference git-conflicts skill
Push rejected Check if branch already exists on fork; suggest --branch override
No upstream remote Auto-detect from gh repo view --json parent or ask user
Upstream/main not found Try upstream/master ; ask user for correct branch name
No commits ahead of upstream Report "Nothing to contribute" and exit
Agentic Optimizations
Context Command
Divergence check git rev-list --left-right --count upstream/main...HEAD
Commits ahead git log --oneline --format='%h %s' upstream/main..HEAD
Validate SHA git rev-parse --verify --short <sha>
Fork owner git remote get-url origin | sed -E 's#.github.com[:/]##; s#.git$##; s#/.##'
Upstream repo git remote get-url upstream | sed -E 's#.*github.com[:/]##; s#.git$##'
Cross-fork PR gh pr create --repo <upstream> --head <fork-owner>:<branch>
Related Skills
-
git-fork-workflow - Fork management and sync strategies
-
git-branch-pr-workflow - General branch and PR patterns
-
git-conflicts - Resolve cherry-pick conflicts
-
git-rebase-patterns - Advanced rebase techniques
-
gh-cli-agentic - GitHub CLI cross-fork PR fields