Split PR Story
Overview
Split one large PR into a mergeable sequence of smaller PRs that each has a clear purpose, compiles independently, and preserves the full intent of the original PR. Prefer actually creating or proposing stacked branches/PRs over only summarizing, unless the user asks for a plan only.
Core Rules
- Treat the original PR as immutable source material. Never mutate, commit to, force-push, close, retarget, rebase, squash, amend, or rewrite the original PR branch unless the user explicitly asks for that exact action.
- Leave the original PR open and recoverable while splitting. If the split is unsatisfactory, the user must be able to return to the original PR unchanged.
- Create new branches and PRs for split parts. Read from the original PR branch or diff, but apply changes onto fresh split branches.
- Define a PR as big when it crosses any of these thresholds: more than 800 changed lines excluding generated files, more than 20 changed files, more than 4 distinct behavioral concerns, more than 2 packages/services touched, or review would require more than about 30 minutes of sustained context.
- Keep every split PR mergeable on its own branch. If a part cannot compile, run tests, or be merged independently, it is not a valid part.
- Prefer stacked PRs when later parts depend on earlier parts. Name them clearly, for example
feature-split-01-test-scaffold,feature-split-02-domain-model,feature-split-03-ui-flow. - Preserve the original PR's full scope. The split plan must account for every meaningful file and behavior in the original diff, including tests, migrations, config, docs, feature flags, generated artifacts, and cleanup.
- Make the PR list tell a story: setup first, contracts and tests next, implementation in dependency order, UI/integration after core behavior, cleanup/docs last.
- Do not split by arbitrary file count. Split by reviewer mental model, dependency order, and user-visible behavior.
- Do not over-split. A larger cohesive PR is better than several tiny PRs that force reviewers to reconstruct context across branches.
- Do not hide risk by putting all tests at the end. Each part should introduce or update the tests that justify that part.
Workflow
1. Establish PR Context
Use local tools first, then GitHub CLI when needed:
git status --short
git branch --show-current
gh pr view <pr> --json number,title,body,baseRefName,headRefName,files,commits,additions,deletions
gh pr diff <pr>
Detect GitHub CLI stack support before planning implementation:
if gh stack --help >/dev/null 2>&1; then
gh stack view --short
fi
Use gh stack when the command is available and the user asks to create, publish, or manage a stacked split. It makes each PR target the preceding layer and records the stack on GitHub. Do not install extensions or enable repository features unless the user asks. If the command is unavailable, the repository does not support the feature, or the user only wants a plan, use normal Git branches and state the fallback.
If GitHub access is unavailable, use the local branch and git diff <base>...HEAD. Identify:
- base branch and head branch
- changed files and generated/vendor files to ignore for size judgment
- dependency direction between files/modules
- tests added, removed, or missing
- whether the current PR already compiles
2. Build The Change Map
Group the diff into logical concerns:
- contracts: schemas, API types, interfaces, database migrations, feature flags
- tests: failing tests, fixtures, snapshot updates, integration tests
- implementation: service/domain logic, persistence, API handlers, workers
- presentation: UI, CLI, docs, user-facing wiring
- operational: config, deployment, telemetry, migrations, backfills
- cleanup: dead code removal, follow-up refactors, generated updates
For each group, record prerequisites and dependents. Treat public contracts, migrations, and shared helpers as early candidates because they unblock later parts. Treat broad mechanical edits as their own part only when they are reviewable without understanding the feature.
3. Choose The Split Strategy
Prefer TDD sequencing when practical:
- Add focused failing tests and test scaffolding that compile without enabling unfinished production paths.
- Add minimal contracts, types, fixtures, or feature flags required by those tests.
- Implement the behavior until the tests pass.
- Add integration/UI/operational wiring.
- Clean up and document.
Use a different strategy when TDD sequencing would create unmergeable or misleading PRs:
- Vertical slices: each part adds one small end-to-end behavior behind a flag.
- Foundation then slices: first part adds shared interfaces or migration-safe schema, later parts add behaviors.
- Compatibility bridge: first part adds backwards-compatible adapters, later parts migrate callers, final part removes the bridge.
- Mechanical first: first part performs pure rename/format/generated regeneration, later parts contain semantic changes.
4. Define Mergeable Parts
For each proposed part, specify:
- title
- base branch: either the original base or the previous split branch
- purpose in one sentence
- included files or commits
- excluded/deferred work
- tests or checks that must pass
- reviewer focus
- risk and rollback notes
- how it advances the story
Validate each proposed part with this reviewability rubric:
- Story: the PR has a clear beginning and end, and its title/body can explain why this slice exists without relying on hidden context from later PRs.
- Cohesion: the files change for one reason. Tests, fixtures, and docs that explain the same behavior belong with that behavior.
- Mergeability: the PR compiles, passes the relevant checks, and can merge independently into its declared base.
- Reviewer load: a reviewer can understand the intent, inspect the important paths, and give a meaningful approval without reading the full original PR.
- Dependency clarity: any dependency on previous split PRs is explicit and mechanical to follow.
- Not too fine-grained: the PR is not merely a helper, one file, or one commit unless that unit has standalone review value.
Use size as a smell, not as the primary rule. A typical target is one reviewable story unit, often under 600 changed lines excluding generated files and under 15 changed files. Exceed that when the slice is cohesive and further splitting would harm reviewability, compileability, or the story. Split further when a PR mixes unrelated concerns, requires different reviewers, hides risk, or cannot be explained in one focused PR description.
5. Create Branches When Asked To Implement
Before editing branches, verify the worktree is clean or identify user changes that must be preserved. Do not discard unrelated changes.
Use non-destructive git operations. Prefer commit-aware splitting when the original PR has meaningful commits; otherwise use patch selection carefully. Do not check out the original PR branch for editing; if it must be checked out to inspect files, switch away before making changes.
When gh stack is available, prefer it for a new stack. Create the branches in bottom-to-top story order, apply only the intended slice to each branch, and validate before adding the next branch:
git fetch origin
git switch <base>
git pull --ff-only
gh stack init --base <base> <split-01>
# apply the first coherent subset from the original PR diff or head ref
# run tests and commit
gh stack add <split-02>
# apply the second subset
# run tests and commit
gh stack add <split-03>
# continue until every slice is committed and validated
If split branches or PRs already exist but were created outside gh stack, link them bottom-to-top instead of rebuilding them:
gh stack link <split-01> <split-02> <split-03>
# or: gh stack link <bottom-pr> <next-pr> <top-pr>
When the user asks to publish the stack, use gh stack submit. Use its interactive editor to supply intentional titles and descriptions. In non-interactive use, gh stack submit --auto creates draft PRs by default; add --open only when the user requests ready-for-review PRs. Report the resulting PR URLs and stack order.
Use gh stack view --short to inspect status. Do not run gh stack sync, gh stack rebase, gh stack merge, gh stack unstack, or any command with a force-push, rebase, merge, deletion, or remote-retargeting effect unless the user explicitly requests that operation. gh stack sync cascade-rebases and pushes stack branches with --force-with-lease; it is not a harmless status command.
Fallback stacked branch flow when gh stack is unavailable:
git fetch origin
git switch <base>
git pull --ff-only
git switch -c <split-01>
# apply the first coherent subset from the original PR diff or head ref
# run tests
# commit
git switch -c <split-02>
# apply the second subset from the original PR diff or head ref
# run tests
# commit
When moving changes from a large branch, use git diff, git apply --cached, git restore --staged, and targeted manual edits as appropriate. Avoid destructive reset/checkout commands unless explicitly approved. Never run commands that push to, reset, rebase, amend, or delete the original PR branch without explicit user approval for that exact branch and action.
6. Validate Like A Merge Queue
For every split part:
- Run the smallest relevant test suite plus compile/typecheck/lint for touched areas.
- Verify the branch diff contains only the intended slice.
- Verify the branch can merge into its declared base.
- Verify later branches still apply after earlier branches are finalized.
- If a part cannot pass checks independently, revise the split before presenting it as mergeable.
If a repository has CI commands, prefer those. Otherwise infer from package manifests, Makefiles, CI config, or existing contributor docs.
Output Format
When planning only, return:
Original PR: #<number> <title>
Size assessment: <why this is big or not big>
Split strategy: <TDD | vertical slices | foundation then slices | compatibility bridge | mechanical first>
Stack tooling: <use gh stack | standard Git branch fallback | not needed for plan>
Reviewability guidance: <why the proposed granularity is right-sized and not over-split>
1. <PR title>
Base: <base branch or previous split>
Purpose: <one sentence>
Includes: <files/behaviors>
Tests: <commands or suites>
Reviewer focus: <what to inspect>
Why this size: <why this is cohesive and reviewable>
2. <PR title>
...
Coverage of original PR:
- <original concern/file group> -> <split PR number>
Risks:
- <risk and mitigation>
When implementing, finish with:
- created branches and their order
- commit SHAs if commits were made
- commands run and pass/fail status
- confirmation that the original PR branch was left unchanged
- any work intentionally left in the original branch
- PR descriptions or
gh pr createcommands if PR creation was requested gh stackcommands used and resulting stack/PR URLs when stack tooling was used