Skip to main content

git-upstream-pr-diverged

Submit a diverged-fork commit to upstream as a clean PR via cherry-pick with re-derive fallback, message scrubbing, and regression checks. Use when direct rebase fails.

Quellinformationen

Repository
laurigates/claude-plugins
Letzte Quellaktivität
2. September 2026 um 11:19
Erkannte Sprache von SKILL.md
Englisch
Sterne
60
Forks
6

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
6 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
git-upstream-pr-diverged
description
Submit a diverged-fork commit to upstream as a clean PR via cherry-pick with re-derive fallback, message scrubbing, and regression checks. Use when direct rebase fails.
args
<sha> [--topic <slug>]
allowed-tools
Bash(git status *), Bash(git diff *), Bash(git log *), Bash(git show *), Bash(git remote *), Bash(git fetch *), Bash(git switch *), Bash(git checkout *), Bash(git cherry-pick *), Bash(git reset *), Bash(git commit *), Bash(git push *), Bash(git stash *), Bash(git rev-list *), Bash(git rev-parse *), Bash(git branch *), Bash(git cat-file *), Bash(git patch-id *), Bash(gh pr *), Bash(gh repo *), Bash(bash *), Bash(uv *), Bash(pytest *), Bash(ruff *), Bash(python3 *), Read, Edit, Write, Grep, Glob, TodoWrite
argument-hint
<sha-to-send-upstream>
created
2026-04-29T00:00:00.000Z
modified
2026-06-18T00:00:00.000Z
reviewed
2026-04-29T00:00:00.000Z
# /git:upstream-pr-diverged Submit a single commit from a heavily-diverged fork back to upstream as a clean, regression-free PR. The simpler `/git:upstream-pr` covers aligned-fork cherry-picks; this skill handles the case where direct rebase fails. ## When to Use This Skill | Use this skill when... | Use `/git:upstream-pr` instead when... | |------------------------|----------------------------------------| | Fork has substantially diverged from upstream | Fork and upstream are roughly aligned | | Cherry-pick may produce many conflicts on shared modules | Single commit applies cleanly | | You need patch-id matching for already-applied content | You want a quick cherry-pick + cross-fork PR | | The change touches files that may be fork-only | All touched files exist upstream | | The PR needs commit-message scrubbing (fork issue refs, Claude trailers) | Commit messages are already upstream-clean | | Pre-flight regression check against upstream baseline matters | The change is trivial enough to skip pre-flight | ## Configuration Per-project configuration lives at `.claude/upstream-pr.local.md` (gitignored). All fields are optional; sensible defaults apply. ```markdown --- upstream_remote: upstream upstream_repo: owner/repo branch_prefix: pr-upstream/ linter_cmd: uv run ruff check test_cmd: uv run pytest -q pr_body_template_path: docs/UPSTREAM_PR_TEMPLATE.md --- # Notes Free-form notes — fork drift hotspots, files to never touch upstream, etc. ``` | Field | Default | Used by | |-------|---------|---------| | `upstream_remote` | `upstream` | All scripts | | `upstream_repo` | Parsed from `git remote get-url <upstream_remote>` | `gh pr create --repo` | | `branch_prefix` | `pr-upstream/` | Branch name in `prepare-branch.sh` | | `linter_cmd` | (empty — pre-flight skipped) | Pre-flight stash-roundtrip | | `test_cmd` | (empty — pre-flight skipped) | Pre-flight stash-roundtrip | | `pr_body_template_path` | (empty — built-in template) | PR body | Add `.claude/*.local.md` to `.gitignore`. ## Context - Current branch: !`git branch --show-current` - Working tree: !`git status --porcelain=v2 --branch` - Remotes: !`git remote -v` - Config file: !`find . -path '*/.claude/*' -maxdepth 2 -name 'upstream-pr.local.md'` ## Parameters Parse from `$ARGUMENTS`: | Parameter | Required | Description | |-----------|----------|-------------| | `<sha>` | Yes | Commit SHA on the fork to send upstream | | `--topic <slug>` | No | Topic slug for branch name; auto-derived from commit subject if omitted | ## Execution Execute this upstream-PR workflow: ### Step 1: Check eligibility Run the eligibility check before touching any branch: ```bash bash "${CLAUDE_SKILL_DIR}/scripts/check-eligibility.sh" <sha> ``` Exit codes drive next steps: | Exit | Meaning | Action | |------|---------|--------| | `0` | Every touched file exists upstream and content is novel | Proceed to Step 2 | | `1` | At least one fork-only file | Stop. Tell the user the change isn't standalone-PR-able; predecessor feature must land first | | `3` | Content already applied upstream under a different SHA | Stop. Report the matching upstream commit; nothing to PR | The patch-id check (`git patch-id --stable`) catches re-applied content from maintainer re-merges or squashes — even when the SHA differs. ### Step 2: Prepare the branch Derive a topic slug from the commit subject if `--topic` was not provided. Then: ```bash bash "${CLAUDE_SKILL_DIR}/scripts/prepare-branch.sh" <topic-slug> <sha> ``` The script: 1. Verifies a clean working tree 2. Re-runs the eligibility check 3. Fetches the upstream remote 4. Creates `<branch_prefix><topic-slug>` from `<upstream_remote>/main` (or `/master`) 5. Cherry-picks `<sha>` 6. Reports any conflict files ### Step 3: Resolve conflicts (if any) When the cherry-pick produces conflicts, **preserve upstream's surrounding shape**, not the fork's. The goal is the smallest readable diff against upstream — a maintainer must see the change make sense in upstream's current code, not in the fork's. #### When to abort and re-derive If the cherry-pick produces dozens of conflict blocks across multiple files (typical when upstream and fork have drifted heavily on shared modules), abort and re-derive instead of fighting hunks: ```bash git cherry-pick --abort git checkout -b <branch> <upstream_remote>/main # Re-apply the change against upstream's actual current files. ``` Re-derive is the right call when: - The original commit is a **mechanical, re-applicable transform** (e.g. `print()` → logging, deprecation rename, lint-rule auto-fixes) — the rules transfer cleanly even if line numbers don't. - Upstream's version of the file has **additional lines the fork removed** — re-derive lets you cover them with the same heuristic rather than rationalizing missing hunks. - The cherry-pick conflict count exceeds roughly **20 blocks across >2 files**. Heuristic: extract the original commit's `before → after` map (e.g. `git show <sha> | grep -E '^[-+].*pattern'`) and use it as the rulebook when re-applying against upstream. The PR body should disclose the re-derive (see template below). ### Step 4: Pre-flight regression check For refactor / cleanup PRs, verify lint and test parity against the **pristine upstream baseline**, not against the fork. This catches stray formatter touches, accidental import reordering, and indentation drift from Edit-tool replacements. If `linter_cmd` and `test_cmd` are configured, run a stash roundtrip: ```bash # Baseline (pristine upstream): git stash push -- <changed-files> <linter_cmd> <changed-files> 2>&1 | tail -1 # error count <test_cmd> 2>&1 | tail -1 # pass count git stash pop # After (with your changes): run the same two commands and compare. ``` Both numbers must match (or improve). Quote both in the PR body's "Testing Performed" section. For Python files, also run `python3 -c "import ast; ast.parse(open(F).read())"` on every edited file — catches indentation breaks that ruff might miss on already-warning-laden upstream code. ### Step 5: Scrub the commit message Run the scrub helper: ```bash bash "${CLAUDE_SKILL_DIR}/scripts/scrub-commit.sh" --check ``` If violations are reported, run without `--check` to amend interactively: ```bash bash "${CLAUDE_SKILL_DIR}/scripts/scrub-commit.sh" ``` The scrub rules: - **Strip local issue references** — `Closes #74`, `Addresses #19`, etc. point at the fork's tracker, not upstream's. - **Strip Claude trailers** — `Co-authored-by: Claude ...`, `Generated with [Claude Code]`. Upstream doesn't follow that convention. - **Soften fork-specific tooling** — if the body cites a tool upstream doesn't run (`bandit B607`, `ty`, `vulture`), describe the underlying problem instead. - **Keep the conventional-commit prefix** — `fix(security):`, `feat(parser):`, etc. The amend wraps `git commit --amend` with `PRE_COMMIT_ALLOW_NO_CONFIG=1` because upstream may have no `.pre-commit-config.yaml` and a locally-installed pre-commit hook would otherwise refuse the commit. ### Step 6: Verify diff hygiene Before pushing, verify with: ```bash git diff <upstream_remote>/main..HEAD ``` Every hunk should be defensible to a maintainer who has never seen the fork. - Don't bundle formatter cleanups with the fix. Keep upstream's existing import order even if the fork's linter would reformat. Upstream may have unusual indentation (e.g. 21-space rather than 20-space blocks) — preserve it; Edit-tool replacements that change leading whitespace by even one character will break the parse. - One commit per PR. If the cherry-pick produced multiple commits, squash before pushing. ### Step 7: Push and open the PR ```bash git push origin <branch> gh pr create --repo <upstream_repo> --base main \ --head <fork-owner>:<branch> \ --title "<conventional-commit subject>" \ --body "<see body template below>" ``` If `pr_body_template_path` is configured, use that template; otherwise use the built-in template: ```markdown ## Description <one or two paragraphs explaining the problem and the fix from the maintainer's perspective — not from the fork's perspective> ## Related Issue(s) None. <or upstream issue numbers only> ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) ## Testing Performed - [x] `<linter_cmd> <changed-files>` — N issues (matches upstream baseline) - [x] `<test_cmd>` — M passed (matches upstream baseline) ## Notes Originally authored on a downstream fork; the branch was cut from `<upstream_repo>:main` and a single commit cherry-picked onto it so it applies cleanly. <If re-derived: "The fork's version of this change collided heavily with upstream's current code; the diff was re-derived against upstream's files using the original commit's transformation rules."> ``` ## Agentic Optimizations | Context | Command | |---------|---------| | Eligibility check | `bash check-eligibility.sh <sha>` (exit 0/1/3) | | Prepare branch | `bash prepare-branch.sh <topic> <sha>` | | Scrub check (CI mode) | `bash scrub-commit.sh --check` | | Diff against upstream | `git diff <upstream_remote>/main..HEAD --stat` | | Cross-fork PR | `gh pr create --repo <upstream_repo> --head <fork-owner>:<branch>` | | Patch-id of HEAD | `git show HEAD \| git patch-id --stable` | ## Related Skills - [git-upstream-pr](../git-upstream-pr/SKILL.md) — simpler cherry-pick path for low-divergence forks - [git-fork-workflow](../git-fork-workflow/SKILL.md) — fork management and upstream sync - [git-conflicts](../git-conflicts/SKILL.md) — conflict resolution patterns
Auf GitHub ansehen