You have git pull
set to do an automatic rebase
(rather than an automatic merge), so this is doing the rough equivalent of git fetch; git rebase project origin/project
.
If all your commits were linear, the rebase would be a no-op after git fetch
brings in no new commits, and you would get the Current branch project is up to date.
message. But, as you said, your commits include a merge-commit of another branch. This is where things are going awry, as the rebase attempts to flatten away the merge. (If you were to rebase with --preserve-merges
it would probably be OK.)
The main thing to recognize here is that there is no need to run git pull
here. Pull is just fetch-then-merge (or fetch-then-rebase if configured to rebase, as yours is). The idea here is to make sure that you have all the commits from the remote. Once you do, you can then git push
them back to the remote and the result will be a fast-forward operation for the remote.
The only time it's not a fast-forward is when someone else sneaks in before you can git push
and gets their commits added to the remote repository.1 In this case, you must git fetch
their commits, then combine them with yours in some fashion (typically a rebase or a merge—i.e., what git pull
does!), then retry your push. If this happens to take you ten seconds while a third group gets their new commits pushed in nine seconds or less, you will again get a "non fast forward" error, and have to repeat the process (potentially forever, if you're slower than everyone else, but in practice this converges quickly).
Using git pull
does not guarantee that you'll be the fastest and "win" the "push race", it's just a convenient way to do the "fetch, then merge-or-rebase" step needed after observing the error. You can simply try the push and see if you get the error ... and if so, use git fetch
rather than git pull
, then decide for yourself how to deal with "losing" the "push race".
1Well, there are one or two other cases, when someone does a force-push to "rewind" or "reset" a branch name, or deletes and recreates a branch, or renames it, or in general causes the whole branch-name-to-commit-ID mapping to change in some unusual / unexpected fashion. But those are not normal cases, except when negotiated ahead of time (some projects have specific "resettable" branches that you're not supposed to depend on behaving "properly", in git terms).