Stacked Pull Requests skill for Codex

Small dependent PRs that merge bottom-up cleanly. Codex designs a stack where every layer builds, passes CI and is safe to deploy alone, then creates it with the team's tool: plain git with --update-refs, GitHub's gh stack extension, or Graphite. It restacks after review fixes without interactive editors, handles the squash-merge case with rebase --onto, fixes CI filters that skip non-main bases, and asks before every force push or PR creation.

  • Engineering Workflow
  • $stacked-pull-requests
  • 166 lines
  • 2 files
  • ~1,800 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- stacked-pull-requests

Installs to ~/.agents/skills/stacked-pull-requests/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $stacked-pull-requests, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Splits a large change into a stack of small dependent pull requests and keeps it healthy - plain git with rebase --update-refs, GitHub native stacks via the gh stack extension, or Graphite's gt CLI - covering branch layout, restacking after review fixes, force-with-lease pushes, retargeting after squash merges, CI that runs on non-main bases, and stack descriptions. Use when a feature is too big for one reviewable PR, when asked to stack or split PRs, when a lower PR changed and the branches above need rebasing, or when a squash merge broke the rest of a stack.

Use it when

  • A feature is too large to review as one PR
  • A lower branch in a stack changed and the rest must follow
  • A squash or rebase merge left the remaining stack conflicting
  • Middle PRs of a stack are not running CI

Use something else when

How to check the result

git log --graph --decorate shows each branch label on its own layer with no duplicate commits, each PR's diff contains only its layer, and CI passed on every PR in the stack.

The mistake it prevents

Restacking with a plain rebase after a squash merge, which replays the already-merged commits and floods the next PR with conflicts; use rebase --onto with the old parent tip.

~/.agents/skills/stacked-pull-requests/SKILL.md

--- name: stacked-pull-requests description: Splits a large change into a stack of small dependent pull requests and keeps it healthy - plain git with rebase --update-refs, GitHub native stacks… license: MIT ---

A healthy stack is a chain of PRs where each one is small enough to review in one sitting (roughly under 400 changed lines), passes CI on its own, is safe to deploy if merging stopped there, and is merged strictly bottom-up. Every branch push that rewrites history is shown to the user first.

Before stacking

  • Read AGENTS.md and CONTRIBUTING.md for merge method (squash, rebase, merge commit) and branch naming. The merge method decides how you restack after each merge.
  • Check what the team already uses: gh extension list (gh stack), which gt (Graphite), a .graphite_repo_config, or jj in the repo. Use their tool; stacks built with a different tool confuse reviewers.
  • Confirm git status is clean and git config rebase.updateRefs (set it to true for plain-git stacks so rebases move every branch in the stack).

Design the split

Order layers so each PR compiles, passes tests and changes no user-visible behaviour until the last one, or hide behaviour behind a flag:

PatternStack
New feature end to end1 schema/migration, 2 domain logic + tests, 3 API, 4 UI behind a flag, 5 flag on
Refactor then feature1 mechanical refactor (no behaviour change), 2 feature using the new shape
Large rename or codemod1 the tool/script, 2 the generated change, 3 manual follow-ups
Risky dependency bump1 compatibility shims, 2 the bump, 3 cleanup of shims

Keep generated and mechanical changes in their own PR; reviewers can skim them. Never put a reviewer-critical change inside a 2,000-line mechanical PR.

Tool choice

SituationUse
GitHub repo, team has native stacked PRs enabledgh stack extension (gh stack init --base main, gh stack rebase, gh stack push; gh stack --help for the rest)
Team uses Graphitegt create, gt modify, gt submit --stack, gt sync, gt restack
No tooling, or a one-offPlain git + gh pr create --base <parent>, described below
Gerrit or Phabricator-style reviewNot this skill’s model; follow that system’s change-per-commit flow

GitHub native stacks evaluate required reviews, checks and CODEOWNERS against the stack’s base branch and keep linear history with gh stack rebase. They require all branches in one repository (no forks).

Plain git workflow

Build the stack

git switch -c feat/orders-1-schema origin/main
# ...commit...
git switch -c feat/orders-2-service      # branches from the previous branch
# ...commit...
git switch -c feat/orders-3-api
# ...commit...
git log --oneline --decorate --graph origin/main..HEAD   # every branch label visible, in order

Open the PRs (outward-facing: confirm titles and bodies with the user first)

git push -u origin feat/orders-1-schema feat/orders-2-service feat/orders-3-api
gh pr create --base main                  --head feat/orders-1-schema  --title "Orders 1/3: schema" --body-file pr1.md
gh pr create --base feat/orders-1-schema  --head feat/orders-2-service --title "Orders 2/3: service" --body-file pr2.md
gh pr create --base feat/orders-2-service --head feat/orders-3-api     --title "Orders 3/3: API" --body-file pr3.md

Each PR’s base is its parent branch, so reviewers see only that layer’s diff. Put the stack map at the top of every body:

**Stack** (merge bottom-up)
1. #101 Orders 1/3: schema
2. #102 Orders 2/3: service  <- this PR
3. #103 Orders 3/3: API

Depends on #101. Safe to deploy alone: yes (service not wired to any route yet).

Address review feedback on a lower PR

Make the fix where it belongs, then move everything above it:

git switch feat/orders-1-schema
# ...edit, commit (or: git commit --fixup=<sha>)...
git switch feat/orders-3-api                    # the top of the stack
git rebase --update-refs feat/orders-1-schema   # replays 2 and 3 onto the new 1, moves branch 2 too

For fixups made at the top that belong lower down, squash them in place without an editor (Codex cannot drive interactive rebases):

git commit --fixup=<sha-in-branch-1>
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --update-refs origin/main

Then push every rewritten branch. This is a force push: show the branch list and get a yes before running it.

git push --force-with-lease --force-if-includes origin \
  feat/orders-1-schema feat/orders-2-service feat/orders-3-api

After the bottom PR merges

git fetch origin
Merge method used for the bottom PRRestack the remainder
Merge commit or rebase mergeFrom the top: git rebase --update-refs origin/main; already-merged commits drop out
Squash mergeThe squashed commit has a new SHA, so the old commits would conflict. From the top: git rebase --update-refs --onto origin/main feat/orders-1-schema (uses the old branch 1 tip as the cut point; do this before deleting that local branch)

Then retarget the next PR if GitHub did not do it automatically (it does when the merged branch is deleted): gh pr edit 102 --base main. Push the rewritten branches with --force-with-lease after confirmation, and delete the merged local branch.

Graphite equivalents

gt create -am "Orders 1/3: schema"     # new branch on top of the current one, with a commit
gt modify -a                           # amend the current branch and restack everything above
gt submit --stack                      # push and create/update PRs for the whole stack
gt sync                                # pull trunk, delete merged branches, restack
gt log short                           # see the stack

gt submit pushes and opens PRs, so confirm with the user before running it.

CI and protection gotchas

  • Workflows filtered with on: pull_request: branches: [main] do not run for PRs whose base is another feature branch. Remove the filter or add the stack’s branch pattern, otherwise middle PRs merge untested. (GitHub native stacks run checks as if each PR targets the base.)
  • Merging an upper PR first merges it into its parent branch, not into main. Its code then arrives in main unreviewed against main’s rules. Always merge bottom-up; consider enabling auto-merge only on the bottom PR.
  • Required approvals usually reset on force push when “dismiss stale reviews” is on. Batch restacks instead of pushing after every small fix.
  • Stacks deeper than about five PRs spend more time restacking than reviewing. Merge the bottom early, or split into two independent stacks.
  • --force-with-lease without a recent fetch can still clobber a teammate’s push to a shared branch; --force-if-includes guards against that. Never force push a branch someone else is committing to without asking.

Verify

  • git log --oneline --graph --decorate origin/main..<top> shows each branch label on the expected commit, in order, with no duplicated commits.
  • Each PR’s “Files changed” contains only its layer (check with gh pr diff 102 --name-only).
  • CI ran and passed on every PR in the stack, not only the bottom one.

Report: stack map with PR numbers, what each layer changes, merge method and restack plan, and any branch that was force-pushed (with the user’s approval).

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Stacked Pull Requests"
  short_description: "Small dependent PRs that merge bottom-up cleanly"
  default_prompt: "$stacked-pull-requests This branch is 3,000 lines. Split it into a stack of reviewable PRs"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem