Search code examples
gitrebasegit-rebase

How to resolve conflicts with git rebase?


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: enter image description here

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:

enter image description here

enter image description here

Now the tree is like this: enter image description here

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: enter image description here

Now the tree is below again: enter image description here

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: enter image description here Because here is conflicts so I rebase master on local: enter image description here The tree turns like enter image description here I thought I can push to remote and merge now. But I run into conflicts on dev itself enter image description here 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?


Solution

  • 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:

    1. Check out dev and squash the 3 commits into one. (You already know how to do this.)
    2. Rebase dev with the 1 good commit onto master. (git rebase master dev) Resolve the conflicts and then continue.
    3. Force push dev. (git push --force-with-lease)
    4. Create a PR to merge dev into master.