Integrating dependent feature branches Jump to heading
A familiar situation: you start a feature, and halfway through realise it needs a change a colleague is making on their own branch — a new API, a schema change, a refactored helper. You cannot wait for their pull request to merge, so you merge their branch into yours. Now your branch contains their unreviewed work, your pull request’s diff shows both changes, and when they rebase their branch after review, yours contains the old version of their commits and conflicts with the new one. Dependent branches are normal; handling them by ad hoc merging is what causes the pain. This page compares the three clean options — stacking, landing the dependency first, and extracting the shared part — and shows how to keep both branches mergeable while the dependency is in review, within feature branch isolation.
When to use this approach Jump to heading
- Your branch needs code that exists only on another unmerged branch.
- You merged a colleague’s branch into yours and the pull request diff now shows both changes.
- A dependency branch was rebased or squash-merged and yours now conflicts with it.
- You are planning a feature in pieces and want each piece reviewable on its own.
Step 1 — Choose a strategy before you depend Jump to heading
Three options cover nearly every case. The right one depends on how big the shared piece is and how soon the dependency can merge.
Step 2 — Option A: extract the shared piece and land it first Jump to heading
Often the dependency is one helper, one migration or one interface. Move just that into a small pull request off main, get it reviewed and merged quickly, then both feature branches build on main.
# Take the shared change out of the colleague's branch onto a fresh branch from main
git switch -c chore/PAY-812-add-schedule-model origin/main
git checkout origin/feat/PAY-801-scheduler -- src/scheduling/model.py migrations/0042_schedule.py
git commit -m "feat(scheduling): add schedule model and migration (PAY-812)"
git push -u origin HEAD && gh pr create --fill Once it merges, both branches rebase or merge main and no longer depend on each other. This is the cleanest option and usually the fastest overall, because a small pull request is reviewed in hours.
Step 3 — Option B: stack your branch on theirs Jump to heading
When you need the whole dependency branch, base your branch on it and open your pull request against their branch, not main. Reviewers then see only your changes. When theirs merges, retarget yours to main.
git switch -c feat/PAY-812-export-ui origin/feat/PAY-801-scheduler
# … work …
git push -u origin HEAD
gh pr create --base feat/PAY-801-scheduler --title "Export UI (stacked on #801)" --fill When the dependency is squash-merged, its original commits are not on main, so a plain rebase replays them and conflicts. Move only your commits:
git fetch origin
git rebase --onto origin/main origin/feat/PAY-801-scheduler feat/PAY-812-export-ui
gh pr edit "$(gh pr view --json number --jq .number)" --base main
git push --force-with-lease The mechanics are in rebasing onto a new base with --onto and, for several levels, updating stacked branches with --update-refs.
Step 4 — Option C: decouple so you do not depend yet Jump to heading
If the dependency will take weeks, depending on it ties your schedule to theirs. Build against an interface or a stub, behind a flag, and connect the real implementation when it lands.
# Your branch codes against an interface the dependency will implement
class Scheduler(Protocol):
def schedule(self, account_id: str, cron: str) -> str: ...
scheduler: Scheduler = get_scheduler() # returns a stub until the real one merges This is branch by abstraction at small scale; the larger form is in branch by abstraction for large changes.
Step 5 — If you already merged their branch in, untangle it Jump to heading
If you merged the colleague’s branch into yours, your pull request now carries their commits. Untangle by rebasing only your commits onto either main (if theirs has merged) or their current branch tip (if not).
# List your own commits, excluding everything from their branch
git log --oneline --no-merges origin/feat/PAY-801-scheduler..HEAD
# Recreate your branch with only those commits, on their latest tip
git rebase --onto origin/feat/PAY-801-scheduler "$(git merge-base HEAD origin/feat/PAY-801-scheduler)" --no-rebase-merges ⚠️ SAFETY WARNING: This rewrites your branch. Push with
--force-with-lease, and check the result withgit range-diffagainst the old tip before pushing. If anything goes wrong, the previous state of your branch is ingit reflogandORIG_HEAD.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Can my pull request merge before the one it depends on? Jump to heading
Not if it is stacked: its base is the dependency branch, so merging it would merge into that branch, not main. Land dependencies first, or decouple.
What if the dependency changes significantly during review? Jump to heading
Rebase your stacked branch onto its new tip as it changes — little and often. With rebase.updateRefs, one rebase updates the whole stack.
Should reviewers review both pull requests together? Jump to heading
Review them separately, in dependency order. The stacked pull request’s diff shows only its own change, which is the point of stacking.
Related Jump to heading
- Feature Branch Isolation — the parent topic.
- Sharing a Feature Branch Between Developers — when two people work on one branch instead.
- Splitting a Branch into Reviewable Pull Requests — creating a stack from one large branch.
- Detecting Squash-Merged Branches — knowing when a dependency has landed.