Git Rebase: Stacked Branches without Re-resolving Conflicts
This is a common situation in Git when working with stacked feature
branches. You want to rebase a branch (say v3
) onto main
after a previous
branch (v2
) has already been merged into main
, without re-resolving
conflicts that were already handled between v2
and v3
.
Scenario 1: v2
was merged normally (not squashed)
main
already contains all changes fromv2
(via merge or fast-forward)v3
was branched fromv2
, and any conflicts betweenv2
andv3
were already resolved
Problem: You want to rebase v3
directly onto main
, but when you do, you are
asked by git
to resolve conflicts that you've already resolved between v2
and v3
.
Step-by-Step Instructions
π§ 1. Ensure you're on v3
π 2. Rebase v3
onto main
, Skipping v2
commits
This command means: "Take all commits from
v3
after it diverged fromv18
, and replay them on top ofmain
."
This works because:
git
will skip thev2
changes (since they're now inmain
)- Only
v3
-specific commits are rebased ontomain
- Previously resolved conflicts between v2 and v3 donβt come back
β Verifying the Rebase
After the rebase completes successfully
1. Confirm your branch base
Ensure
v3
is now based off the latestmain
tip and the history looks clean.
2. Double-check your changes
You should only see changes that were unique to v3
, not v2
3. Push safely
This safely updates the remote v3
branch with your new rebased commits.
Why --force-with-lease
?
Itβs safer than plain --force because it checks if the remote branch has changed since your last fetch If someone else has pushed to the branch in the meantime, it will refuse to overwrite their work
Example
Before rebase
After merging v2
into main
Now you run
After rebase
You now have a clean history, no redundant conflict resolution and v3
is based
on the lates main.
Scenario 2: Rebase v3
onto main
after v2
was squashed-merged
v3
was branched offv2
v2
was squashed-merged intomain
- You want to rebase
v3
ontomain
, without reapplying or conflicting with the changes already merged fromv2
Step-by-Step Instructions
π 1. Find the common ancestor (fork point) between v2
and v3
Let' say this returns
abc123
. Save that commit hash.
π 2. Start the rebase
This means: "Take all commits from
v3
that came after it diverged fromv2
, and replay them ontomain
."
β οΈ 3. Resolve Conflicts
You might see
I. Manually resolve the conflict
Open the conflicting files using your IDE and fix them.
Since you've likely already resolved this conflict before (in v3
when building
on top of v2
), reapply the same resolution logic.
II. Stage the Resolved Files
III. Continue the rebase
git
will replay the next commit in v3
. Repeat step I - III
for each commit
that causes a conflict.
β 4. If the rebase becomes too messy
You can cancel and go back to how v3
was before the rebase
Enable git
conflict memory
This tells Git to remember how you resolved a conflict, so if the same one comes up in the future, Git can auto-resolve it for you.
git config --global rerere.enabled true
β 5. Verify Rebase
Check the commit graph
Make sure
v3
is now based onmain
.
Check that only your v3
changes are present
π 6. Push Safely
This safely updates the remote v3
branch with your new rebased commits.
Example
Before squash merge and rebase
After v2
is squash-merged into main
(as S
)
S
is a squashed version ofD
+E
, so Git sees no shared history.
Rebase v3
onto main
, skipping over v2
commits
Now git
replays only F
and G
on top of main
.
Iβve run into this exact situation enough times β rebasing stacked branches
after a squash merge β that I finally decided to write it down. It always trips
me up when I forget which branch to use with --onto
, or when conflicts pop up
that I thought I already resolved.
Hopefully, this note helps future me (and maybe you too) avoid the same
confusion. git
can be tricky, but with a clear mental model and the right
steps, it's not as bad as it feels in the moment.
Until the next rebase panic. π