]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/tag.c
Merge branch 'jk/bundle-use-dash-for-stdfiles'
[thirdparty/git.git] / builtin / tag.c
index 82fcfc0982423f3c7ee90fe43d30295023cc7873..adcaa547b0d57094fa811f5f81e3a601cc05e2b2 100644 (file)
@@ -9,6 +9,7 @@
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
+#include "hex.h"
 #include "refs.h"
 #include "object-store.h"
 #include "tag.h"
 #include "oid-array.h"
 #include "column.h"
 #include "ref-filter.h"
+#include "date.h"
 
 static const char * const git_tag_usage[] = {
-       N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
-               "\t\t<tagname> [<head>]"),
+       N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+          "        <tagname> [<commit> | <object>]"),
        N_("git tag -d <tagname>..."),
-       N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]\n"
-               "\t\t[--format=<format>] [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
+       N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
+          "        [--points-at <object>] [--column[=<options>] | --no-column]\n"
+          "        [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+          "        [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
        N_("git tag -v [--format=<format>] <tagname>..."),
        NULL
 };
@@ -146,7 +150,7 @@ static int verify_tag(const char *name, const char *ref,
                      const struct object_id *oid, void *cb_data)
 {
        int flags;
-       const struct ref_format *format = cb_data;
+       struct ref_format *format = cb_data;
        flags = GPG_VERIFY_VERBOSE;
 
        if (format->format)
@@ -177,9 +181,6 @@ static const char tag_template_nocleanup[] =
 
 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;
@@ -188,13 +189,10 @@ static int git_tag_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "tag.sort")) {
                if (!value)
                        return config_error_nonbool(var);
-               parse_ref_sorting(sorting_tail, value);
+               string_list_append(cb, value);
                return 0;
        }
 
-       status = git_gpg_config(var, value, cb);
-       if (status)
-               return status;
        if (!strcmp(var, "tag.forcesignannotated")) {
                force_sign_annotate = git_config_bool(var, value);
                return 0;
@@ -239,7 +237,7 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
 {
        if (sign && do_sign(buf) < 0)
                return error(_("unable to sign the tag"));
-       if (write_object_file(buf->buf, buf->len, tag_type, result) < 0)
+       if (write_object_file(buf->buf, buf->len, OBJ_TAG, result) < 0)
                return error(_("unable to write tag file"));
        return 0;
 }
@@ -293,9 +291,7 @@ static void create_tag(const struct object_id *object, const char *object_ref,
 
                /* write the template message before editing: */
                path = git_pathdup("TAG_EDITMSG");
-               fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
-               if (fd < 0)
-                       die_errno(_("could not create file '%s'"), path);
+               fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
 
                if (opt->message_given) {
                        write_or_die(fd, buf->buf, buf->len);
@@ -366,7 +362,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
                strbuf_addstr(sb, "object of unknown type");
                break;
        case OBJ_COMMIT:
-               if ((buf = read_object_file(oid, &type, &size)) != NULL) {
+               if ((buf = read_object_file(oid, &type, &size))) {
                        subject_len = find_commit_subject(buf, &subject_start);
                        strbuf_insert(sb, sb->len, subject_start, subject_len);
                } else {
@@ -374,7 +370,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
                }
                free(buf);
 
-               if ((c = lookup_commit_reference(the_repository, oid)) != NULL)
+               if ((c = lookup_commit_reference(the_repository, oid)))
                        strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
                break;
        case OBJ_TREE:
@@ -433,12 +429,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        int create_reflog = 0;
        int annotate = 0, force = 0;
        int cmdmode = 0, create_tag_object = 0;
-       const char *msgfile = NULL, *keyid = NULL;
-       struct msg_arg msg = { 0, STRBUF_INIT };
+       char *msgfile = NULL;
+       const char *keyid = NULL;
+       struct msg_arg msg = { .buf = STRBUF_INIT };
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
        struct ref_filter filter;
-       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
+       struct ref_sorting *sorting;
+       struct string_list sorting_options = STRING_LIST_INIT_DUP;
        struct ref_format format = REF_FORMAT_INIT;
        int icase = 0;
        int edit_flag = 0;
@@ -472,7 +470,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_REF_SORT(sorting_tail),
+               OPT_REF_SORT(&sorting_options),
                {
                        OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
                        N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
@@ -484,10 +482,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
                OPT_END()
        };
+       int ret = 0;
+       const char *only_in_list = NULL;
 
        setup_ref_filter_porcelain_msg();
 
-       git_config(git_tag_config, sorting_tail);
+       git_config(git_tag_config, &sorting_options);
 
        memset(&opt, 0, sizeof(opt));
        memset(&filter, 0, sizeof(filter));
@@ -523,15 +523,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        finalize_colopts(&colopts, -1);
        if (cmdmode == 'l' && filter.lines != -1) {
                if (explicitly_enable_column(colopts))
-                       die(_("--column and -n are incompatible"));
+                       die(_("options '%s' and '%s' cannot be used together"), "--column", "-n");
                colopts = 0;
        }
-       if (!sorting)
-               sorting = ref_default_sorting();
+       sorting = ref_sorting_options(&sorting_options);
        ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
        filter.ignore_case = icase;
        if (cmdmode == 'l') {
-               int ret;
                if (column_active(colopts)) {
                        struct column_options copts;
                        memset(&copts, 0, sizeof(copts));
@@ -542,29 +540,36 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                ret = list_tags(&filter, sorting, &format);
                if (column_active(colopts))
                        stop_column_filter();
-               return ret;
+               goto cleanup;
        }
        if (filter.lines != -1)
-               die(_("-n option is only allowed in list mode"));
-       if (filter.with_commit)
-               die(_("--contains option is only allowed in list mode"));
-       if (filter.no_commit)
-               die(_("--no-contains option is only allowed in list mode"));
-       if (filter.points_at.nr)
-               die(_("--points-at option is only allowed in list mode"));
-       if (filter.reachable_from || filter.unreachable_from)
-               die(_("--merged and --no-merged options are only allowed in list mode"));
-       if (cmdmode == 'd')
-               return delete_tags(argv);
+               only_in_list = "-n";
+       else if (filter.with_commit)
+               only_in_list = "--contains";
+       else if (filter.no_commit)
+               only_in_list = "--no-contains";
+       else if (filter.points_at.nr)
+               only_in_list = "--points-at";
+       else if (filter.reachable_from)
+               only_in_list = "--merged";
+       else if (filter.unreachable_from)
+               only_in_list = "--no-merged";
+       if (only_in_list)
+               die(_("the '%s' option is only allowed in list mode"), only_in_list);
+       if (cmdmode == 'd') {
+               ret = delete_tags(argv);
+               goto cleanup;
+       }
        if (cmdmode == 'v') {
                if (format.format && verify_ref_format(&format))
                        usage_with_options(git_tag_usage, options);
-               return for_each_tag_name(argv, verify_tag, &format);
+               ret = for_each_tag_name(argv, verify_tag, &format);
+               goto cleanup;
        }
 
        if (msg.given || msgfile) {
                if (msg.given && msgfile)
-                       die(_("only one -F or -m option is allowed."));
+                       die(_("options '%s' and '%s' cannot be used together"), "-F", "-m");
                if (msg.given)
                        strbuf_addbuf(&buf, &(msg.buf));
                else {
@@ -628,10 +633,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                printf(_("Updated tag '%s' (was %s)\n"), tag,
                       find_unique_abbrev(&prev, DEFAULT_ABBREV));
 
-       UNLEAK(buf);
-       UNLEAK(ref);
-       UNLEAK(reflog_msg);
-       UNLEAK(msg);
-       UNLEAK(err);
-       return 0;
+cleanup:
+       ref_sorting_release(sorting);
+       strbuf_release(&buf);
+       strbuf_release(&ref);
+       strbuf_release(&reflog_msg);
+       strbuf_release(&msg.buf);
+       strbuf_release(&err);
+       free(msgfile);
+       return ret;
 }