That is a misunderstanding of what rebase does, and I believe this is what has created this very frustrating situation.
What might have happened
Suppose you have the follow situation (which I believe is what you described).
master o---o---o---o---o---o
\
feature1 A---B---C
\
feature2 X---Y---Z
You're done with work on feature1
, but there are some commits on master that haven't been tested with the feature1
changes. So, to update feature1
you do the following:
git checkout feature1
git rebase master
This results in the following situation:
master o---o---o---o---o---o
\ \
feature1 \ A'---B'---C'
\
feature2 A---B---C---X---Y---Z
Wait, what? Why are there two copies of A-B-C
!?
That's what rebase
does. Rebase
makes NEW commits starting from the base given in the command (master
in this situation).
What probably happened next
Now that feature1
has been updated with the latest from master
, you need to update feature2
. So, you follow the same process:
git checkout feature2
git rebase feature1
This results in the following situation:
master o---o---o---o---o---o
\
feature1 A'---B'---C'
\
feature2 A"---B"---C"---X---Y---Z
Uh oh.
As you can see, after a few times through this cycle you end up in a very bad place where you have to resolve "conflicts" that are just applying the same changes over and over.
How to fix the current mess
Just bite the bullet and use merge
. Seriously, this is the fastest way to deal with it. Update the feature branches from master
with git merge master
and then merge
the feature branches back into master (when appropriate).
Alternatively, you can delve into the dark magic that is interactive rebase. Use the -i
flag when running git rebase
and you will see a list of all commits it is attempting to reapply. Remove the duplicates and carry on your merry way. I don't like this approach because it's easy to make a mistake, and it's a PIA to recover from these mistakes.
How to avoid this going forward
Detailed article
In short, you need to tell git to ignore the duplicated commits. Updating feature1
using rebase
was fine, the problem happened with feature2
.
git checkout feature2
git rebase --onto feature1 feature1@{1} feature2
Which gets us
master o---o---o---o---o---o
\
feature1 A'---B'---C'
\
feature2 X'---Y'---Z'
Exactly what we wanted!
So, what is this command doing?
git rebase --onto feature1 feature1@{1} feature2
--onto feature1
- we're going move these commits onto the branch feature1
feature1@{1}
- We just rebase
'd feature1
, so we need to get the previous commit (IE the one before the rebase). This is the start of the commit range we're moving
feature2
- This is the end of the commit range we're moving
NOTE: feature1@{1}
will work when used as part of the process described in the article, but may not be correct if other git commands are run between updating feature1
and feature2
. In this instance, you can substitute this for the raw commit id - obtained by reviewing the output from git log
while on feature2
and selecting the last commit from feature1
("C" in the example given here).
Other Good Reading: