I have
A--B--C master
\
D branch0
Then I squash B
and C
into B'
.
How do I rebase branch0
such that it looks like this:
A--B' master
\
D branch0
I have
A--B--C master
\
D branch0
Then I squash B
and C
into B'
.
How do I rebase branch0
such that it looks like this:
A--B' master
\
D branch0
Use the --onto
argument to git rebase, which changes the baseline that git replays work on.
git checkout branch0
At this state you should still see C in your git history.
git rebase --onto B' C
This translates to: Take all commits in my current branch since commit C (In your case that's just D) and play back on top of B'
You can also use the optional <branch>
argument to do both the checkout and rebase at once:
git rebase --onto B' C branch0
I've run into a similar problem when using squash-merge on PRs when you have branches off of branches.
My common example is if I have one feature branch (feature-a
). I push some commits to that branch. Then I create another feature branch off of that (feaure-b-off-a
). Then I squash-merge feature-a
into main, I'll see duplicate commits in the PR of feature-b-off-a
into main.
To fix this, we can use a rebase --onto
like the accepted answer, here. But the manual work of that is finding C
(I refer to common-ancestor below). Rewritten another way:
git rebase --onto main common-ancestor feature-b-off-a
common-ancestor
and feature-b-off-a
and rebase them onto main
Fortunately, git
has a way of finding the common ancestor between two branches:
git merge-base feature-b-off-a feature-a
# This will print out the 'common-ancestor' commit between the commits/branches causing the problem
git merge-base feature-b-off-a feature-a
# Take all the commits between common-ancestor and feature-b-off-a and rebase them onto main
git rebase --onto main <common-ancestor> feature-b-off-a
# Then you'll need to force push since it's a rebase
git push -f origin feature-b-off-a
Note: This assumes your flow is squash-merging both into main
git config --global alias.rebase-onto '!f() { git rebase --onto main $(git merge-base "$1" "$2") "$1"; }; f'
Which you'd call with:
git rebase-onto feature-b-off-a feature-a
# Then you'll need to force push since it's a rebase
git push -f origin feature-b-off-a
One quick way I can think of is,
git checkout branch0
Note down the sha of the D commit by git log
git checkout master
Now rename the branch0 to branch1
git branch -m branch0 branch1
A--B' master
\
D branch1
Now delete branch1
git branch -D branch1
Create a branch0 again as follows.
git checkout -b branch0
A--B' - master&branch0
After the above command master and branch0 are same. Only change we need to make in branch0 is get the commit D.
git cherry-pick D
Now branch0 looks as follows
A--B' master
\
D branch0