Stage Branch Discipline
Overview
Treat stage as an integration branch for testing combined changes, not as a place to create a second source of truth. The healthy state is simple: every meaningful change visible on stage already exists in some PR branch that can merge to the primary branch. If that rule holds, promoting tested changes is mostly a matter of merge order. If it was broken, first reconstruct which PR branch each stage change belongs to, then compare stage against those branches and rebuild a clean merge path.
Stage Discipline
- Do not add unique fixes directly to
stageif they belong to a specific PR or feature branch. - Treat
stageas the place where branch results are combined and tested, not as the source of truth for follow-up fixes. - If testing on
stagereveals a bug in an existing PR, fix the owning PR branch first. If that branch is no longer usable, create a refreshed replacement PR from the primary branch. - Bring the same fix into
stageonly to keepstagealigned with the branch that should eventually merge. - Prefer “branch first, then stage” over “stage first, then reconstruct later”.
- If this discipline is followed,
stageshould have no meaningful changes that exist only onstage, and the final merge should not require inventing replay logic.
Workflow
- Inventory the delta.
Compare the primary branch and stage with git log --first-parent, git log --left-right --cherry-pick, and git diff --stat.
- Classify every change.
Separate:
- existing open PR branches that already target the primary branch
- direct commits on
stage - stage-only branches that were merged into
stagebut never opened against the primary branch - commits later canceled by explicit reverts
Then decide which direct stage commits are legitimate one-off integration commits and which ones are process debt that should have lived in a PR branch.
- Keep the
stage -> mainorstage -> primaryumbrella PR out of the merge path.
Use it only as evidence of intent. Do not merge it directly if the goal is a clean, reviewable replay onto the primary branch.
- Refresh stale branches on top of the current primary branch.
If an older PR no longer merges cleanly or its checks are stale, create a fresh branch from the primary branch, cherry-pick the relevant commits, and use that refreshed PR as the merge path.
- Route follow-up fixes back to their source branch.
If testing on stage uncovers a bug in an already-merged PR branch, fix that branch or replace it with a refreshed PR. Avoid leaving the fix only on stage, because that creates hidden history that later has to be reconstructed by hand.
- Create one worktree per merge unit.
For every new PR branch, create a dedicated worktree from the primary branch. For follow-ups to an existing non-primary branch, use a dedicated worktree there too, but prefer replacing it with a fresh primary-based PR if that is cleaner.
- Merge foundations first.
Put tooling and workflow fixes first if later cherry-picks or commits depend on them.
- Merge behavior, then docs, then cleanup.
Recommended order:
- tooling foundations
- backend or frontend behavior changes
- integration or e2e coverage
- docs and runbooks
- cleanup or dedup fixes
- Verify the primary branch against
stageafter each wave.
Use git diff primary..stage and inspect only the remaining files. Also compare stage against the source PR branches when recovering from stage-only drift, so you can prove that no functional change was lost. Distinguish between:
- true missing functionality
- acceptable drift where the primary branch is now better than
stage - generated file drift
- intentional tooling drift
- Close superseded PRs explicitly.
Leave a short comment that links the replacement PR, then close the old PR. Do the same for the umbrella stage PR once the split merge set has landed.
Decision Rules
- If a stage-only commit is already fully represented by a merged replacement PR, do not replay the original commit just to preserve SHA identity.
- If a conflict resolution in a refreshed PR already matches
stage, and a later follow-up commit becomes empty, treat that as confirmation that the desired state is already included. - If the primary branch contains a post-stage safety fix, do not regress it just to force byte-for-byte equality with
stage. - If only locale text, generated artifacts, or similar outputs differ, classify that separately from functional behavior.
- If a bugfix was created only on
stage, treat that as process debt and move it into the owning PR branch or a refreshed replacement PR before considering the replay complete. - If the question is “did we lose anything from those older PRs?”, answer it by diffing the original PR branches against the current primary branch and describing functional loss, generated drift, or improvements in the primary branch.
Reporting
When summarizing the split, produce:
- merged PRs
- refreshed or replacement PRs
- closed superseded PRs
- remaining diff between the primary branch and
stage, labeled as functional, generated, or intentional
Reference
For command patterns and closure language, read references/checklist.md.