push: return reject reasons as a bitset

Pass all rejection reasons back from transport_push().  The logic is
simpler and more flexible with regard to providing useful feedback.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: add advice for rejected tag reference

Advising the user to fetch and merge only makes sense if the rejected
reference is a branch.  If none of the rejections are for branches, just
tell the user the reference already exists.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: keep track of "update" state separately

If the reference exists on the remote and it is not being removed, then
mark as an update.  This is in preparation for handling tags (lightweight
and annotated) exceptionally.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: flag updates that require force

Add a flag for indicating an update to a reference requires force.
Currently the `nonfastforward` flag is used for this when generating the
status message.  A separate flag insulates dependent logic from the
details of set_ref_status_for_push().

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: require force for refs under refs/tags/

References are allowed to update from one commit-ish to another if the
former is an ancestor of the latter.  This behavior is oriented to
branches which are expected to move with commits.  Tag references are
expected to be static in a repository, though, thus an update to
something under refs/tags/ should be rejected unless the update is
forced.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: require force for annotated tags

Do not allow fast-forwarding of references that point to a tag object.
Updating from a tag is potentially destructive since it would likely
leave the tag dangling.  Disallowing updates to a tag also makes sense
semantically and is consistent with the behavior of lightweight tags.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: clarify rejection of update to non-commit-ish

Pushes must already (by default) update to a commit-ish due to the fast-
forward check in set_ref_status_for_push().  But rejecting for not being
a fast-forward suggests the situation can be resolved with a merge.
Flag these updates (i.e., to a blob or a tree) as not forwardable so the
user is presented with more appropriate advice.

While updating *from* a tag object is potentially destructive, updating
*to* a tag is not.  Additionally, a push to the refs/tags/ hierarchy is
already excluded from fast-forwarding, and refs/heads/ is protected from
anything but commit objects by a check in write_ref_sha1().  Thus
someone fast-forwarding to a tag is probably not doing so by accident.
Since updating to a tag is benign and unlikely to cause confusion, allow
it in case someone finds the behavior useful.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: cleanup push rules comment

Rewrite to remove inter-dependencies amongst the rules.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: rename config variable for more general use

The 'pushNonFastForward' advice config can be used to squelch several
instances of push-related advice.  Rename it to 'pushUpdateRejected' to
cover other reject scenarios that are unrelated to fast-forwarding.
Retain the old name for compatibility.

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
push: allow already-exists advice to be disabled

Add 'advice.pushAlreadyExists' option to disable the advice shown when
an update is rejected for a reference that is not allowed to update at
all (verses those that are allowed to fast-forward.)

Signed-off-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>