tag: advise on nested tags
authorDenton Liu <liu.denton@gmail.com>
Thu, 4 Apr 2019 18:25:15 +0000 (11:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Apr 2019 01:52:35 +0000 (10:52 +0900)
Robert Dailey reported confusion on the mailing list about a nested
tag which was most likely created by mistake. Jeff King noted that
this isn't a very common case and creating a tag-to-a-tag can be a
user-error.

Suggest that it may be a mistake with an advice message when
creating such a tag.  Those who do want to create a tag that point
at another tag regularly can turn it off with the usual advice
mechanism.

Reported-by: Robert Dailey <rcdailey.lists@gmail.com>
Helped-by: Jeff King <peff@peff.net>
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
[jc: fixed test style and tweaked the log message]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config/advice.txt
advice.c
advice.h
builtin/tag.c
t/t7004-tag.sh

index 8862042..ec4f6ae 100644 (file)
@@ -90,4 +90,6 @@ advice.*::
        waitingForEditor::
                Print a message to the terminal whenever Git is waiting for
                editor input from the user.
+       nestedTag::
+               Advice shown if a user attempts to recursively tag a tag object.
 --
index 567209a..ce5f374 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -26,6 +26,7 @@ int advice_ignored_hook = 1;
 int advice_waiting_for_editor = 1;
 int advice_graft_file_deprecated = 1;
 int advice_checkout_ambiguous_remote_branch_name = 1;
+int advice_nested_tag = 1;
 
 static int advice_use_color = -1;
 static char advice_colors[][COLOR_MAXLEN] = {
@@ -81,6 +82,7 @@ static struct {
        { "waitingForEditor", &advice_waiting_for_editor },
        { "graftFileDeprecated", &advice_graft_file_deprecated },
        { "checkoutAmbiguousRemoteBranchName", &advice_checkout_ambiguous_remote_branch_name },
+       { "nestedTag", &advice_nested_tag },
 
        /* make this an alias for backward compatibility */
        { "pushNonFastForward", &advice_push_update_rejected }
index f875f8c..cb5d361 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -26,6 +26,7 @@ extern int advice_ignored_hook;
 extern int advice_waiting_for_editor;
 extern int advice_graft_file_deprecated;
 extern int advice_checkout_ambiguous_remote_branch_name;
+extern int advice_nested_tag;
 
 int git_default_advice_config(const char *var, const char *value);
 __attribute__((format (printf, 1, 2)))
index faae364..32948fa 100644 (file)
@@ -206,7 +206,14 @@ struct create_tag_options {
        } cleanup_mode;
 };
 
-static void create_tag(const struct object_id *object, const char *tag,
+static const char message_advice_nested_tag[] =
+       N_("You have created a nested tag. The object referred to by your new is\n"
+          "already a tag. If you meant to tag the object that it points to, use:\n"
+          "\n"
+          "\tgit tag -f %s %s^{}");
+
+static void create_tag(const struct object_id *object, const char *object_ref,
+                      const char *tag,
                       struct strbuf *buf, struct create_tag_options *opt,
                       struct object_id *prev, struct object_id *result)
 {
@@ -218,6 +225,9 @@ static void create_tag(const struct object_id *object, const char *tag,
        if (type <= OBJ_NONE)
                die(_("bad object type."));
 
+       if (type == OBJ_TAG && advice_nested_tag)
+               advise(_(message_advice_nested_tag), tag, object_ref);
+
        strbuf_addf(&header,
                    "object %s\n"
                    "type %s\n"
@@ -551,7 +561,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (create_tag_object) {
                if (force_sign_annotate && !annotate)
                        opt.sign = 1;
-               create_tag(&object, tag, &buf, &opt, &prev, &object);
+               create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object);
        }
 
        transaction = ref_transaction_begin(&err);
index 0b01862..e285686 100755 (executable)
@@ -1700,6 +1700,17 @@ test_expect_success '--points-at finds annotated tags of tags' '
        test_cmp expect actual
 '
 
+test_expect_success 'recursive tagging should give advice' '
+       sed -e "s/|$//" <<-EOF >expect &&
+       hint: You have created a nested tag. The object referred to by your new is
+       hint: already a tag. If you meant to tag the object that it points to, use:
+       hint: |
+       hint:   git tag -f nested annotated-v4.0^{}
+       EOF
+       git tag -m nested nested annotated-v4.0 2>actual &&
+       test_i18ncmp expect actual
+'
+
 test_expect_success 'multiple --points-at are OR-ed together' '
        cat >expect <<-\EOF &&
        v2.0