Do not allow fast-forwarding of references that point to a tag object. This keeps the behavior consistent with lightweight tags. Additionally, allowing the reference to update could leave the old object dangling. Signed-off-by: Chris Rorvick <chris@xxxxxxxxxxx> --- Documentation/git-push.txt | 10 +++++----- remote.c | 11 +++++++++-- t/t5516-fetch-push.sh | 21 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 09bdec7..7a04ce5 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -52,11 +52,11 @@ updated. + The object referenced by <src> is used to update the <dst> reference on the remote side. By default this is only allowed if <dst> is not -under refs/tags/, and then only if it can fast-forward <dst>. 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>. See EXAMPLES below for -details. +a tag (annotated or lightweight), and then only if it can fast-forward +<dst>. 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>. See +EXAMPLES below for details. + `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`. + diff --git a/remote.c b/remote.c index 012b52f..f5bc4e7 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 8f024a0..6009372 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" && -- 1.8.0.209.gf3828dc -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html