I'm pretty sure you left out a step:
Step 2.5: You pushed feature_branch
.
At that moment feature
looked like:
m1-m2-f1-f2
In step 3, after you rebased feature_branch
onto master
, feature_branch
looked something like:
m1-m2-m3-f1'-f2'
(Note the "prime" here in f1'
and f2'
, which is used to signify that they are like f1
and f2
but slightly different, e.g. each has a new commit ID, and in this case also a new parent commit ID, and committer datetime, etc.)
Now when you tried to push, you probably saw a message like:
Your branch and 'origin/feature_branch' have diverged, and have 3 and 2 different commits each, respectively.
This is because origin/feature_branch
has commits f1
and f2
and your local branch no longer has those commits, since now they are f1'
and f2'
which are different commit IDs. When Git detects this, it always tells you to pull and then push, but in your case, you don't want to pull because that will merge the old version of your branch back into your current, better, version. By pulling here you end up with duplicate versions of your commits. Instead you want to force push after purposefully rewriting your branch, such as with amend, or rebase.
The Fix:
To prevent this next time, as mentioned in Phillipe's comment, after rebasing your branch, if you've already pushed it before, don't pull like Git tells you to, but instead you should use git push --force-with-lease
.
For now you can use git reflog
to either find f2'
or even f2''
and then git reset --hard <commit-id-you-want>
. Then you can force push your feature_branch
to remove the merge with the old version of those commits.
The Explanation:
The fact that you didn't do that explains everything you witnessed. Since you had conflicts replaying f1
and f2
on top of m3
, after resolving them your new state is compatible with f1'
and f2'
only. When you pulled, that merged in the original versions of f1
and f2
again which aren't compatible with the new state, so you had conflicts again. After resolving them and completing the merge, your branch probably looked something like this:
m1-m2-m3-f1'-f2'-MC
\---f1--f2-/
When you rebased onto master
a second time in step 5, you now have 5 commits that aren't on master
, and, when you rebase the merge commits fall out by default, so only the 4 commits will be replayed. (Had you added the option -i
to the rebase you could have witnessed it.) Presumably commit m4
didn't introduce any conflicts with f1'
and f2'
, so replaying them as "1 of 4" and "2 of 4" went just fine, and at that moment your temporary branch looked like this:
m1-m2-m3-m4-f1''-f2''
# conflict on replaying f1
This explains why you already saw the changes from f1
and f2
there, but it was still stuck on trying to replay the original f1
and f2
; thus it had conflicts again because the merge commit that resolved the conflicts last time isn't being replayed during the rebase. If you're still in that state you can actually elect to skip those commits as you no longer need them, or just quit where you are:
git rebase --quit
Now your branch should look like:
m1-m2-m3-m4-f1''-f2''
If you are detached you could just repoint your branch to this commit:
git switch -C feature_branch # recreate branch pointing to f2''
# then
git push --force-with-lease