skip to content

How would you land a chain of five dependent GitHub pull requests without blocking the rest of your team?

level: principalimportance: nice to knowfreq 28%

answer

  1. Each pull request's base is the one below it
  2. GitHub does something helpful when the parent merges
  3. The base pointer moves, the commits do not
  4. Squash merging is what makes children conflict
  5. Consider whether the dependency was necessary at all

basics

~20 s

Base each pull request on the previous one's branch so every diff stays small, land the bottom of the stack first, and prefer a merge method that preserves the parent's commits. GitHub retargets the children's base branches automatically as each parent merges.

solid answer

~60 s

A stack means pull request B targets A's branch rather than the default branch, so each review shows only its own diff. Landing it well comes down to a few decisions: - **Land bottom-up and fast.** The bottom pull request should be the least controversial so it merges quickly and the stack does not calcify. - **Rely on GitHub's retargeting.** When a parent merges and its head branch is deleted, GitHub automatically retargets any open pull request that was based on it to the parent's base branch. - **Mind the merge method.** Squash and rebase merging replace the parent's commits with new ones, so each child then carries near-duplicate commits and needs replaying onto the new base. A merge commit preserves the parent's commits and keeps the stack cheapest. - **Keep upper entries as drafts** until their parent is close to landing, so reviewers are not asked to review code whose base is still moving. The real judgment call is whether to stack at all: often the better answer is smaller independent changes behind a feature flag.

go deeper

for a junior

Know that a pull request can target another branch instead of the default branch, and that this is how a large change gets split into reviewable pieces.

for a middle

Explain what GitHub does to a child pull request when its base branch merges and is deleted, and why the child's commits still need attention afterwards.

for a senior

Show that you have maintained one: bottom-up landing, re-running checks after retargeting, and the conflict pattern a squash-merged parent creates for its children.

for a principal

Own the strategic call. Argue when stacking is the right tool versus feature-flagged independent changes, and connect the repository's merge-method policy to how expensive stacks are for everyone.

## What a stack is on GitHub GitHub always diffs a pull request against its base branch. If you point B's base at A's branch instead of the default branch, B's diff shows only B's work. Repeat this and you get a stack: five reviewable units, each small, each dependent on the one below. This is the standard answer to "my change is 3,000 lines and nobody will review it" without resorting to a single unreviewable pull request. ## The mechanics that decide whether a stack is pleasant or painful **Automatic retargeting.** When you merge a pull request and delete its head branch, GitHub retargets any open pull requests that used that branch as their base, pointing them at the merged pull request's base. So merging A quietly moves B to target the default branch. This is the single most important platform behaviour to know here, and it is why stacks work at all without tooling. **The merge method dominates the pain.** Retargeting changes the base *pointer*; it does not rewrite B's commits. If A merged with a merge commit, A's commits are still present on the default branch with their original identities, so B's copies of them are the same objects and B's diff collapses correctly to just B's work. If A was squash-merged or rebase-merged, the default branch now holds *different* commits carrying the same changes, while B still carries the originals. B's diff then shows A's changes again and conflicts are likely, so B has to be replayed onto the updated default branch before it is reviewable. This is precisely the point where the tree split matters: the replay itself is a Git operation, but the choice that created the problem is the repository's merge-method policy. **Review discipline.** A stack asks reviewers to hold context across five pull requests. Keep the upper ones as drafts until their parent is nearly landed, describe the stack in each body ("2 of 5; depends on #401"), and put the risky change as high in the stack as you can so the safe foundation lands early. ## Alternatives you should weigh out loud The interviewer is usually probing whether you reach for stacking reflexively. Three alternatives: - **Independent small changes behind a feature flag.** Each merges to the default branch immediately, in any order, with no stack to maintain. This is normally the better default: the dependency was often only in your head, not in the code. - **A shared integration branch.** All five pull requests target one long-lived branch that merges to the default branch at the end. Simpler than a stack for the authors, but it defers integration risk and the final merge is large. - **One pull request with clean commits.** Sometimes honest: if the five parts are genuinely inseparable, one pull request reviewed commit by commit beats five pull requests nobody can reason about individually. ## Operating a stack that has to exist - **Land bottom-up, quickly.** Every day the bottom sits unmerged, the default branch drifts and the whole stack ages. - **Prefer merge commits for the intermediate entries** if your repository allows a per-pull-request choice, because preserving commit identity is what makes retargeting cheap. - **Re-run checks after retargeting.** A child that was green against its parent's branch is not necessarily green against the default branch; the required checks must pass in the new context before merging. - **Do not delete branches manually mid-stack.** Deleting a parent's branch while children are open, without merging, orphans them; let the merge do the deletion so retargeting fires. - **Watch for a merge queue.** Where one is in use, entries land through the queue rather than instantly, so the stack drains at the queue's pace and it is worth checking how your team's queue treats dependent entries. ## What a strong answer sounds like Name the topology (each pull request based on the previous), name the platform behaviour you are relying on (automatic base retargeting on merge), name the failure mode (squash or rebase merging leaves the children carrying duplicate commits), and then step up a level: stacks are a workaround for changes that could not be made independently, so the first question is whether feature flags and smaller independent changes remove the dependency entirely. Owning that framing — rather than just describing the mechanics — is what makes this a lead-level answer.

  • What exactly happens to an open pull request whose base branch was just merged and deleted?
    GitHub retargets it to the merged pull request's base branch, so the child now targets the default branch instead of a branch that no longer exists. Its commits are untouched, so if the parent was squashed or rebase-merged the child still carries the original copies and needs replaying before its diff is clean.
  • Why is a merge commit often the kindest merge method for an intermediate pull request in a stack?
    Because it preserves the parent's commits with their original identities on the base branch. The child's copies are then the same objects, so after retargeting its diff collapses to just its own work. Squash and rebase merging create new commits, leaving the child with near-duplicates that conflict.
  • When would you refuse to build a stack at all?
    When the dependency is incidental rather than real. If each piece can ship behind a feature flag or as an inert addition, merge them independently in any order — no retargeting, no rebasing, no reviewer holding five contexts. Reserve stacks for genuinely sequential changes where an intermediate state cannot exist safely.

saying these in an interview costs you the question

  • Thinks GitHub rebases the child branches when the parent merges
  • Assumes a squash-merged parent leaves the child's diff clean
  • Points every pull request at main and calls it a stack
  • Deletes a parent branch manually while children are open
  • Treats stacking as always better than feature-flagged independent changes

context