I've two git branches in test. And I'm making the episode of Rebase conflict. However I'm too poor on git and it's easy to make a problem but hard to solve.
Now the tree of commit is like this:
What I want to do is squash commits on local dev
and rebase dev
to master
(where dev
is -b
from master
). Off course there will be conflicts as expected.
Squash local
I checked out dev
and squashed:
Question 1: Why the master is off side the line instead of on some line?
Push dev to remote
The I want to push local to remote and before that, I pulled remote code. And surprise, local commit is override by remote:
Question 2: How can I push my local edit to remote?
merge to master
Anyway, I just want to merge code to master
on remote. So I ignored the I-don't-understand things and created a PR on remote:
Because here is conflicts so I
rebase
master on local:
The tree turns like
I thought I can push to remote and merge now. But I run into conflicts on
dev
itself
What's tough now I cannot resolve the conflicts. These conflicts struggled with me. No matter what I tried the error exists.
Question Last: How can resolve the conflicts and rebase master
, and merge to master
?
Question 1: Why the master is off side the line instead of on some line?
The command you ran, while having dev
checked out, didn't have anything to do with master
:
git rebase -i HEAD~3
You ended up squashing the top 3 commits and replaying the new squashed commit onto HEAD~3
. If you wanted to squash those three commits and also replay it onto master
, you could have done this:
git rebase -i HEAD~3 dev --onto master
# or in this case, since HEAD~3 happens to also be the
# merge-base of dev and master, the above command simplifies to:
git rebase -i master
Since you would have had conflicts though, my personal preference is usually to squash first just like you did, and then do a second rebase onto the new target for resolving the conflicts, rather than trying to squash and resolve conflicts at the same time.
I want to push local to remote and before that, I pulled remote code. And surprise, local commit is override by remote... (Implied Question 1.5: Why is that?)
This happened because you have your pull
command configured to do a rebase
instead of the default merge
. So that means when you used the command git pull
it was substituted with git pull --rebase
, and effectively that was the same as doing:
git rebase origin/dev dev
So what happened there is it replayed all of the commits on dev
that weren't on origin/dev
, which was just your one new squashed commit. But all the changes in that commit were already on origin/dev
so effectively that was the same as doing, with dev
checked out:
git reset --hard @{u}
# which is just shorthand for
git reset --hard origin/dev
That's why your squashed commit disappeared and you ended up back where you started.
Question 2: How can I push my local edit to remote?
Any time you rewrite your local branch that you have already pushed before, your branch will be "diverged" and this means you cannot do a regular push, but instead you must force push:
git push --force-with-lease
When you tried to simply use git push
, and Git told you to try git pull
instead, Git was giving you bad advice. (Sometimes I tell people never to use git pull
, partially for this reason. Instead I suggest using the separate commands of git fetch
, then looking at the remote origin/*
branch, and then using git merge
or git rebase
if desired.)
Question Last: How can resolve the conflicts and rebase master, and merge to master?
Note the problems you had at the end were just repeating the same problems from the beginning: You rebased the 3 original commits onto master
instead of the squashed commit. You finished resolving those conflicts (3 times instead of just once), but then made the mistake of using git pull
again, which tried to rebase those 3 new commits onto the 3 old ones...
What you need to do now, is:
dev
and squash the 3 commits into one. (You already know how to do this.)dev
with the 1 good commit onto master
. (git rebase master dev
) Resolve the conflicts and then continue.dev
. (git push --force-with-lease
)dev
into master
.