Merge branch 'js/mingw-gcc-stack-protect'
[gitweb.git] / builtin / tag.c
index 9a19ffb49f68d7c0318f650d34d0edbcd6db81d3..e0a4c25382846f801c43cd1093ffb0ffa63f975f 100644 (file)
 #include "ref-filter.h"
 
 static const char * const git_tag_usage[] = {
-       N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]"),
+       N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
+               "\t\t<tagname> [<head>]"),
        N_("git tag -d <tagname>..."),
-       N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]"
-               "\n\t\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]"),
+       N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]\n"
+               "\t\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]"),
        N_("git tag -v [--format=<format>] <tagname>..."),
        NULL
 };
 
 static unsigned int colopts;
 static int force_sign_annotate;
+static int config_sign_tag = -1; /* unspecified */
 
 static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
                     struct ref_format *format)
@@ -143,6 +145,11 @@ static int git_tag_config(const char *var, const char *value, void *cb)
        int status;
        struct ref_sorting **sorting_tail = (struct ref_sorting **)cb;
 
+       if (!strcmp(var, "tag.gpgsign")) {
+               config_sign_tag = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "tag.sort")) {
                if (!value)
                        return config_error_nonbool(var);
@@ -205,7 +212,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 tag 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)
 {
@@ -215,7 +229,10 @@ static void create_tag(const struct object_id *object, const char *tag,
 
        type = oid_object_info(the_repository, object, NULL);
        if (type <= OBJ_NONE)
-           die(_("bad object type."));
+               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"
@@ -338,6 +355,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
 {
        struct msg_arg *msg = opt->value;
 
+       BUG_ON_OPT_NEG(unset);
+
        if (!arg)
                return -1;
        if (msg->buf.len)
@@ -390,13 +409,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_GROUP(N_("Tag creation options")),
                OPT_BOOL('a', "annotate", &annotate,
                                        N_("annotated tag, needs a message")),
-               OPT_CALLBACK('m', "message", &msg, N_("message"),
-                            N_("tag message"), parse_msg_arg),
+               { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+                 N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg },
                OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
                OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
                OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
-               OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
-                       N_("how to strip spaces and #comments from message")),
+               OPT_CLEANUP(&cleanup_arg),
                OPT_STRING('u', "local-user", &keyid, N_("key-id"),
                                        N_("use another key to sign the tag")),
                OPT__FORCE(&force, N_("replace the tag if exists"), 0),
@@ -410,8 +428,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
                OPT_MERGED(&filter, N_("print only tags that are merged")),
                OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
-               OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
-                            N_("field name to sort on"), &parse_opt_ref_sorting),
+               OPT_REF_SORT(sorting_tail),
                {
                        OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
                        N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
@@ -431,15 +448,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        memset(&opt, 0, sizeof(opt));
        memset(&filter, 0, sizeof(filter));
        filter.lines = -1;
+       opt.sign = -1;
 
        argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0);
 
-       if (keyid) {
-               opt.sign = 1;
-               set_signing_key(keyid);
-       }
-       create_tag_object = (opt.sign || annotate || msg.given || msgfile);
-
        if (!cmdmode) {
                if (argc == 0)
                        cmdmode = 'l';
@@ -452,6 +464,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (cmdmode == 'l')
                setup_auto_pager("tag", 1);
 
+       if (opt.sign == -1)
+               opt.sign = cmdmode ? 0 : config_sign_tag > 0;
+
+       if (keyid) {
+               opt.sign = 1;
+               set_signing_key(keyid);
+       }
+       create_tag_object = (opt.sign || annotate || msg.given || msgfile);
+
        if ((create_tag_object || force) && (cmdmode != 0))
                usage_with_options(git_tag_usage, options);
 
@@ -548,7 +569,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);
@@ -559,7 +580,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
        ref_transaction_free(transaction);
-       if (force && !is_null_oid(&prev) && oidcmp(&prev, &object))
+       if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
                printf(_("Updated tag '%s' (was %s)\n"), tag,
                       find_unique_abbrev(&prev, DEFAULT_ABBREV));