Search code examples
gitmergerebase

Git error Updates were rejected because the tip of your current branch is behind


I faced this issue for many times, so I want to share with you to get what's wrong with my approach.

I have two branches in the remote repository, dev and master. dev was originated from the master and have got 2 new commits. (which is common)

Now I wanted to update remote dev branch with a few more commits and make a merge request to update the remote master branch eventually.

So I did the following

  1. Fetched and checked out dev. e.g: git fetch & git checkout dev
  2. Committed two times to local dev, in the meanwhile remote master was updated by another team mate and it has 3 new commits
  3. So I checked out local master and pulled the latest origin master. e.g: git checkout master & git pull origin master
  4. After the pull, I rebased the local dev against the local master. e.g: git rebase master dev
  5. And I pushed my local dev to the remote dev. e.g: git push origin dev

But it gave me an error Updates were rejected because the tip of your current branch is behind its remote counterpart.

Even though git push -f will work, as far as I understood, my local dev was originated from the remote dev and has new commits, so it can't be behind the remote one.


Solution

  • my local dev was originated from the remote dev and has new commits, so it can't be behind the remote one.

    Yes it can and it is, in the sense that Git means it.

    After the pull, I rebased the local dev against the local master. e.g: git rebase master dev

    That's the reason. Rebasing changes history. Simply, it replaces the rebased commits with new ones. You cannot move a commit, ever, not with rebase or anything else; you can only copy the commit as a different commit. It may have the same commit message but that's just part of what was copied.

    Do you see? No? Okay, let's start before your step 1, where dev split off from master and had two new commits. Call those commits A and B. It was like that on the remote, and (1) you fetched and checked out that, so it was like that on your local dev too: your dev has the same A and B since the split from master.

    (Now ignore everything else you did locally with dev...)

    Then (2) master grew and (3) you pulled it and (4) rebased dev onto it. That replaced your A and B with new commits; call them AA and BB.

    Now (5) you try to push dev. But the remote dev still has the old A and B. And your local dev doesn't! So the remote dev has commits that you don't have in your local dev, and the push is rejected. You cannot push without force unless your history is a continuation of the remote's history — and it isn't.