Problem recap: you work on a ticket, commit, and attempt to push, only to be greeted with:
Then, as the error message says, you try a
git push again, but:
and you are left utterly confused (especially if you haven't touched the master at all).
The problem occurs because of how git push/pull work, combined with the poorly chosen default behavior of
git push, compounded by the misleading (incomplete) error message.
git push attempts to sync all branches upstream, not just the current branch. Here "sync" means "upload all necessary changes, and make the tip of the remote branch the same as the tip of the local branch." Secondly, this is not atomic -- some branches may sync successfully, others may fail. That is what happens in #1 above. The syncing of
tickets/1831 succeeds, but the syncing of master doesn't. That's why in #3 there is no message about
tickets/1831 any more.
The sync of
master failed because someone else has pushed a new commit to the remote:
Remote Local master: master: D | C C | | B B | | A A
As git translates your
git push quite literally as 'Do everything necessary to make the commit C the tip of the remote master', it refuses to do so as there's no fast-forward path from D to C. And that is what it (tersely) reports.
So while git advises you to do
git pull, it does not warn you that
git pull checks only the current branch. That is why in # 2 above,
git pull will say that everything is up to date (when the
master clearly isn't), because
git push has succeeded for
tickets/1831 in # 1.
So there's a subtle, annoying asymmetry between
git pull and
git push. Knowing all that, the workaround is easy:
Or, just ignore the
git push error message for branches you're not working on.
Can anything be done about this? The root cause of the problem is the unexpected asymmetry of
git pull and
git push. The former syncs down only the current branch, while the latter attempts to sync up all branches. Everything would be much better if either
git pullfetched+merged all branches or
git pushwould push only the current branch upstream
The former cannot be done. The latter can be:
--global will set this as default for all repos that you work with on that account/machine.
So if we try it now:
Now there are no more annoying messages about branches we're not working on (master). Voilà!
The downside is that now you have to manually push each branch upstream, but, realistically, this *is* what one wants 99.99% of the time. It's unclearn why this isn't the default; perhaps it's related to history and backwards compatibility.
Helpful on-line references: