From: Chris Rorvick Date: Fri, 30 Nov 2012 01:41:38 +0000 (-0600) Subject: push: require force for annotated tags X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=40eff1799983b958d6dbe09fb499ad505bcf6f8d;p=git.git 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 Signed-off-by: Junio C Hamano --- diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 09bdec75b..7a04ce5f2 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -52,11 +52,11 @@ updated. + The object referenced by is used to update the reference on the remote side. By default this is only allowed if is not -under refs/tags/, and then only if it can fast-forward . By having -the optional leading `+`, you can tell git to update the ref even -if it is not allowed by default (e.g., it is not a fast-forward.) This -does *not* attempt to merge into . See EXAMPLES below for -details. +a tag (annotated or lightweight), and then only if it can fast-forward +. By having the optional leading `+`, you can tell git to update +the ref even if it is not allowed by default (e.g., it is not a +fast-forward.) This does *not* attempt to merge into . See +EXAMPLES below for details. + `tag ` means the same as `refs/tags/:refs/tags/`. + diff --git a/remote.c b/remote.c index 012b52f6f..f5bc4e726 100644 --- a/remote.c +++ b/remote.c @@ -1281,9 +1281,16 @@ int match_push_refs(struct ref *src, struct ref **dst, static inline int is_forwardable(struct ref* ref) { + struct object *o; + if (!prefixcmp(ref->name, "refs/tags/")) return 0; + /* old object must be a commit */ + o = parse_object(ref->old_sha1); + if (!o || o->type != OBJ_COMMIT) + return 0; + return 1; } @@ -1323,8 +1330,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, * to overwrite it; you would not know what you are losing * otherwise. * - * (4) if both new and old are commit-ish, and new is a - * descendant of old, it is OK. + * (4) if old is a commit and new is a descendant of old + * (implying new is commit-ish), it is OK. * * (5) regardless of all of the above, removing :B is * always allowed. diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 8f024a08f..60093728f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -950,6 +950,27 @@ test_expect_success 'push requires --force to update lightweight tag' ' ) ' +test_expect_success 'push requires --force to update annotated tag' ' + mk_test heads/master && + mk_child child1 && + mk_child child2 && + ( + cd child1 && + git tag -a -m "message 1" Tag && + git push ../child2 Tag:refs/tmp/Tag && + git push ../child2 Tag:refs/tmp/Tag && + >file1 && + git add file1 && + git commit -m "file1" && + git tag -f -a -m "message 2" Tag && + test_must_fail git push ../child2 Tag:refs/tmp/Tag && + git push --force ../child2 Tag:refs/tmp/Tag && + git tag -f -a -m "message 3" Tag HEAD~ && + test_must_fail git push ../child2 Tag:refs/tmp/Tag && + git push --force ../child2 Tag:refs/tmp/Tag + ) +' + test_expect_success 'push --porcelain' ' mk_empty && echo >.git/foo "To testrepo" &&