I have a branchA and branchB (main branch). After some code review, I tried to run this first in branchA to pull changes from branchB
git pull --rebase origin branchB
followed by
git push origin -u branchA
but I get this error
! [rejected](fetch first)
error: failed to push some refs to '<url>'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Also i see this on command prompt
After that, I did just "git pull" (without any arguments) and it works just fine. What happens in running "git pull"
(Note: this answer simplifies. But not by much!)
Consider this situation, looking at two versions of the same branch:
A - B - C - X (remote)
A - B - C - Y (local)
How can these be reconciled? Only one way: by merging. If we merge the remote version into the local version, we get this:
-- X --
/ \
A - B - C M (local)
\ /
-- Y --
...where M is a newly created merge commit that combines the contributions from X and Y.
Well, that is what git pull
does. It copies the remote version of the branch down to you, and merges it with your local version.
But it is illegal to do that same thing on the remote — by saying git push
. You are not permitted to form a merge commit in that way. The reconciliation can only be performed on your computer, locally. You cannot, therefore, push when the remote has commits on this branch that you do not have.
Hence when you attempt to do it, the remote Git refuses. The solution of pull
-then-push
solves the problem. After you pull, you have all the commits that the remote has, and so the push becomes legal.
Extra information:
Consider the situation after the pull but before the push. Remember, the remote still has:
A - B - C - X (remote)
And you now have:
-- X --
/ \
A - B - C M (local)
\ /
-- Y --
When you push, the remote is able to accept these commits just by adding M to the end of its version of the branch, like this:
A - B - C - X - M (remote)
\ /
- Y -
It's true that it must also accommodate Y, but the point is that no new merge commit is needed in order to do that. This is called a fast-forward — no new commits are created, but existing pushed commits are just appended to the branch.
So the rule, technically, is that you cannot push unless it is possible to fast-forward on the remote. When we started, that was not possible: somebody must create a true merge commit in order to reconcile these branches, and that somebody is not going to be the remote. By doing a pull first, and allow the non-fast-forward merge to happen on the local, you make it possible to fast-forward on the remote.