I have a branch A, with several commits I want to squash, and from this branch has been created an other branch (B), with several commits I want also to squash.
I rebased the branch A from develop, and squashed all commits in one commit. OK.
I then try to rebase B from the A (whose SHA1 changed because of previous commit), but the window Git shows me the list of commits since the old branch A, not the squashed one.
Why ?
Here's what's happening, made clearer with some graphs. Initially, you start out with 3 branches, develop
, A
, and B
:
a-b-c < develop
\
d-e-f < A
\
g-h-i < B
Now you run git rebase -i develop A
(equivalent to git checkout A && git rebase -i develop
) and squash all commits:
a-b-c < develop
|\
| f' < A
\
d-e-f-g-h-i < B
f'
is the squashed commit. Branch B
still references the unrelated and untouched commit i
. Since every commit keeps an (immutable) reference to its parent commit (or parent commits), the original, unsquashed commit d
, e
, and f
are still reachable from B
.
When you now run git rebase A B
(or the equivalent git checkout B && git rebase A
), then Git will replay all commits reachable from B
that are not reachable from A
. Looking at the graph it is clear that these are commits d..i
(d, e, f, g, h, i), including the original, unsquashed commits. Consequently, you would end up with a-b-c-f'-d-e-f-g-h-i
– but since f'
already contains the changes of d
, e
, and f
, they cannot be reapplied and will result in conflicts.
What you want to do instead is specify the upstream and new base explicitly: git rebase --onto A f B
(interactive rebase is supported as well with -i
). Running this command results in the following history:
a-b-c < develop
\
f' < A
\
g'-h'-i' < B
or a-b-c-f'-i'
if you decide to squash g..i
into a single commit.