TL;DR
If you’re only pushing one branch, there is no difference.
git push -f origin branch
and
git push origin +branch
are exact equivalents. The difference arises when you’re pushing more than one branch with a single git push.
In a nutshell, the optional + gives you finer control than -f does: if you’re pushing more than one ref at a time, the + allows you to specify which of the pushed refs get force-pushed, whereas --force (or -f) applies to all the refs that are getting pushed.
More details
What the git-push man page tells you
The most basic form of git push that involve one or more refspec(s) is
git push <repository> <refspec>...
The form that the <refspec>... argument must satisfy is described in the git-push man page thus:
<refspec>...Specify what destination ref to update with what source object. The format of a `<refspec>` parameter is an optional plus `+`, followed by the source object `<src>`, followed by a colon `:`, followed by the destination ref `<dst>`.
So, just to be clear, the syntax for <refspec> is
[+]<src>[:<dest>]
If :<dst> is omitted, the same ref as <src> will be updated… unless the remote.<repository>.push entry (if any) in your Git config says otherwise.
Further down in the git-push man page, you find
By having the optional leading
+, you can tell Git to update the<dst>
ref even if it is not allowed by default (e.g., it is not a
fast-forward.) This does not attempt to merge<src>into<dst>.
And still further down:
Note that
--forceapplies to all the refs that are pushed, hence
using it withpush.defaultset tomatchingor with multiple push
destinations configured withremote.*.pushmay overwrite refs other
than the current branch (including local refs that are strictly behind
their remote counterpart). To force a push to only one branch, use a+
in front of the refspec to push (e.ggit push origin +masterto force
a push to themasterbranch).
Example
Consider a local repo with two branches, master and develop, which you want to push (with a single git push command) to an origin remote.
-
git push origin master developwill push both branches, but neither will get force-pushed. -
git push origin +master developwill push both branches, but onlymasterwill get force-pushed. -
git push origin master +develop, conversely, will push both branches, but onlydevelopwill get force-pushed. -
git push origin +master +developwill force-push both branches. It’s an exact equivalent togit push -f origin master develop.