aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/tag.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/tag.c')
-rw-r--r--builtin/tag.c122
1 files changed, 65 insertions, 57 deletions
diff --git a/builtin/tag.c b/builtin/tag.c
index 75dece0e4f..f036cf32f5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -6,13 +6,18 @@
* Based on git-tag.sh and mktag.c by Linus Torvalds.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "tag.h"
-#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
#include "revision.h"
@@ -21,13 +26,16 @@
#include "column.h"
#include "ref-filter.h"
#include "date.h"
+#include "write-or-die.h"
static const char * const git_tag_usage[] = {
- N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
- " <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"
- " [--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
};
@@ -39,13 +47,7 @@ static int config_sign_tag = -1; /* unspecified */
static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
struct ref_format *format)
{
- struct ref_array array;
- struct strbuf output = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
char *to_free = NULL;
- int i;
-
- memset(&array, 0, sizeof(array));
if (filter->lines == -1)
filter->lines = 0;
@@ -63,21 +65,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
if (verify_ref_format(format))
die(_("unable to parse format string"));
filter->with_commit_tag_algo = 1;
- filter_refs(&array, filter, FILTER_REFS_TAGS);
- ref_array_sort(sorting, &array);
-
- for (i = 0; i < array.nr; i++) {
- strbuf_reset(&output);
- strbuf_reset(&err);
- if (format_ref_array_item(array.items[i], format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- putchar('\n');
- }
+ filter_and_format_refs(filter, FILTER_REFS_TAGS, sorting, format);
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
free(to_free);
return 0;
@@ -109,7 +98,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
return had_error;
}
-static int collect_tags(const char *name, const char *ref,
+static int collect_tags(const char *name UNUSED, const char *ref,
const struct object_id *oid, void *cb_data)
{
struct string_list *ref_list = cb_data;
@@ -135,7 +124,7 @@ static int delete_tags(const char **argv)
if (!ref_exists(name))
printf(_("Deleted tag '%s' (was %s)\n"),
item->string + 10,
- find_unique_abbrev(oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
free(oid);
}
@@ -143,7 +132,7 @@ static int delete_tags(const char **argv)
return result;
}
-static int verify_tag(const char *name, const char *ref,
+static int verify_tag(const char *name, const char *ref UNUSED,
const struct object_id *oid, void *cb_data)
{
int flags;
@@ -176,10 +165,9 @@ static const char tag_template_nocleanup[] =
"Lines starting with '%c' will be kept; you may remove them"
" yourself if you want to.\n");
-static int git_tag_config(const char *var, const char *value, void *cb)
+static int git_tag_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- int status;
-
if (!strcmp(var, "tag.gpgsign")) {
config_sign_tag = git_config_bool(var, value);
return 0;
@@ -192,9 +180,6 @@ static int git_tag_config(const char *var, const char *value, void *cb)
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;
@@ -202,7 +187,11 @@ static int git_tag_config(const char *var, const char *value, void *cb)
if (starts_with(var, "column."))
return git_column_config(var, value, "tag", &colopts);
- return git_color_default_config(var, value, cb);
+
+ if (git_color_config(var, value, cb) < 0)
+ return -1;
+
+ return git_default_config(var, value, ctx, cb);
}
static void write_tag_body(int fd, const struct object_id *oid)
@@ -213,7 +202,7 @@ static void write_tag_body(int fd, const struct object_id *oid)
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
- orig = buf = read_object_file(oid, &type, &size);
+ orig = buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
return;
if (parse_signature(buf, size, &payload, &signature)) {
@@ -264,11 +253,10 @@ static const char message_advice_nested_tag[] =
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)
+ struct object_id *prev, struct object_id *result, char *path)
{
enum object_type type;
struct strbuf header = STRBUF_INIT;
- char *path = NULL;
type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
@@ -292,7 +280,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
int fd;
/* write the template message before editing: */
- path = git_pathdup("TAG_EDITMSG");
fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (opt->message_given) {
@@ -304,9 +291,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,
struct strbuf buf = STRBUF_INIT;
strbuf_addch(&buf, '\n');
if (opt->cleanup_mode == CLEANUP_ALL)
- strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template), tag, comment_line_char);
else
- strbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template_nocleanup), tag, comment_line_char);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -320,7 +309,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,
}
if (opt->cleanup_mode != CLEANUP_NONE)
- strbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);
+ strbuf_stripspace(buf,
+ opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
@@ -334,10 +324,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
path);
exit(128);
}
- if (path) {
- unlink_or_warn(path);
- free(path);
- }
}
static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
@@ -364,7 +350,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))) {
+ if ((buf = repo_read_object_file(the_repository, oid, &type, &size))) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
@@ -431,11 +417,12 @@ 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;
+ 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;
+ struct ref_filter filter = REF_FILTER_INIT;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
@@ -471,6 +458,8 @@ 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_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_REF_SORT(&sorting_options),
{
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
@@ -485,13 +474,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
};
int ret = 0;
const char *only_in_list = NULL;
+ char *path = NULL;
setup_ref_filter_porcelain_msg();
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_tag_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
memset(&opt, 0, sizeof(opt));
- memset(&filter, 0, sizeof(filter));
filter.lines = -1;
opt.sign = -1;
@@ -591,7 +586,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (argc > 2)
die(_("too many arguments"));
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
if (strbuf_check_tag_ref(&ref, tag))
@@ -619,7 +614,9 @@ 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, object_ref, tag, &buf, &opt, &prev, &object);
+ path = git_pathdup("TAG_EDITMSG");
+ create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
+ path);
}
transaction = ref_transaction_begin(&err);
@@ -627,19 +624,30 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
ref_transaction_update(transaction, ref.buf, &object, &prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
- ref_transaction_commit(transaction, &err))
+ ref_transaction_commit(transaction, &err)) {
+ if (path)
+ fprintf(stderr,
+ _("The tag message has been left in %s\n"),
+ path);
die("%s", err.buf);
+ }
+ if (path) {
+ unlink_or_warn(path);
+ free(path);
+ }
ref_transaction_free(transaction);
if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
printf(_("Updated tag '%s' (was %s)\n"), tag,
- find_unique_abbrev(&prev, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &prev, DEFAULT_ABBREV));
cleanup:
ref_sorting_release(sorting);
+ ref_filter_clear(&filter);
strbuf_release(&buf);
strbuf_release(&ref);
strbuf_release(&reflog_msg);
strbuf_release(&msg.buf);
strbuf_release(&err);
+ free(msgfile);
return ret;
}