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 -d <tagname>..."),
- N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]"
+ 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
}
typedef int (*each_tag_name_fn)(const char *name, const char *ref,
- const unsigned char *sha1, const void *cb_data);
+ const struct object_id *oid, const void *cb_data);
static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
const void *cb_data)
{
const char **p;
- char ref[PATH_MAX];
+ struct strbuf ref = STRBUF_INIT;
int had_error = 0;
- unsigned char sha1[20];
+ struct object_id oid;
for (p = argv; *p; p++) {
- if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
- >= sizeof(ref)) {
- error(_("tag name too long: %.*s..."), 50, *p);
- had_error = 1;
- continue;
- }
- if (read_ref(ref, sha1)) {
+ strbuf_reset(&ref);
+ strbuf_addf(&ref, "refs/tags/%s", *p);
+ if (read_ref(ref.buf, oid.hash)) {
error(_("tag '%s' not found."), *p);
had_error = 1;
continue;
}
- if (fn(*p, ref, sha1, cb_data))
+ if (fn(*p, ref.buf, &oid, cb_data))
had_error = 1;
}
+ strbuf_release(&ref);
return had_error;
}
static int delete_tag(const char *name, const char *ref,
- const unsigned char *sha1, const void *cb_data)
+ const struct object_id *oid, const void *cb_data)
{
- if (delete_ref(NULL, ref, sha1, 0))
+ if (delete_ref(NULL, ref, oid->hash, 0))
return 1;
- printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
return 0;
}
static int verify_tag(const char *name, const char *ref,
- const unsigned char *sha1, const void *cb_data)
+ const struct object_id *oid, const void *cb_data)
{
int flags;
const char *fmt_pretty = cb_data;
if (fmt_pretty)
flags = GPG_VERIFY_OMIT_STATUS;
- if (gpg_verify_tag(sha1, name, flags))
+ if (gpg_verify_tag(oid->hash, name, flags))
return -1;
if (fmt_pretty)
- pretty_print_ref(name, sha1, fmt_pretty);
+ pretty_print_ref(name, oid->hash, fmt_pretty);
return 0;
}
return git_default_config(var, value, cb);
}
-static void write_tag_body(int fd, const unsigned char *sha1)
+static void write_tag_body(int fd, const struct object_id *oid)
{
unsigned long size;
enum object_type type;
char *buf, *sp;
- buf = read_sha1_file(sha1, &type, &size);
+ buf = read_sha1_file(oid->hash, &type, &size);
if (!buf)
return;
/* skip header */
free(buf);
}
-static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result)
+static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
{
if (sign && do_sign(buf) < 0)
return error(_("unable to sign the tag"));
- if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
+ if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0)
return error(_("unable to write tag file"));
return 0;
}
} cleanup_mode;
};
-static void create_tag(const unsigned char *object, const char *tag,
+static void create_tag(const struct object_id *object, const char *tag,
struct strbuf *buf, struct create_tag_options *opt,
- unsigned char *prev, unsigned char *result)
+ struct object_id *prev, struct object_id *result)
{
enum object_type type;
- char header_buf[1024];
- int header_len;
+ struct strbuf header = STRBUF_INIT;
char *path = NULL;
- type = sha1_object_info(object, NULL);
+ type = sha1_object_info(object->hash, NULL);
if (type <= OBJ_NONE)
die(_("bad object type."));
- header_len = snprintf(header_buf, sizeof(header_buf),
- "object %s\n"
- "type %s\n"
- "tag %s\n"
- "tagger %s\n\n",
- sha1_to_hex(object),
- typename(type),
- tag,
- git_committer_info(IDENT_STRICT));
-
- if (header_len > sizeof(header_buf) - 1)
- die(_("tag header too big."));
+ strbuf_addf(&header,
+ "object %s\n"
+ "type %s\n"
+ "tag %s\n"
+ "tagger %s\n\n",
+ oid_to_hex(object),
+ typename(type),
+ tag,
+ git_committer_info(IDENT_STRICT));
if (!opt->message_given) {
int fd;
if (fd < 0)
die_errno(_("could not create file '%s'"), path);
- if (!is_null_sha1(prev)) {
+ if (!is_null_oid(prev)) {
write_tag_body(fd, prev);
} else {
struct strbuf buf = STRBUF_INIT;
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
- strbuf_insert(buf, 0, header_buf, header_len);
+ strbuf_insert(buf, 0, header.buf, header.len);
+ strbuf_release(&header);
if (build_tag_object(buf, opt->sign, result) < 0) {
if (path)
}
}
-static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb)
+static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
{
enum object_type type;
struct commit *c;
strbuf_addstr(sb, rla);
} else {
strbuf_addstr(sb, _("tag: tagging "));
- strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV);
+ strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV);
}
strbuf_addstr(sb, " (");
- type = sha1_object_info(sha1, NULL);
+ type = sha1_object_info(oid->hash, NULL);
switch (type) {
default:
strbuf_addstr(sb, _("object of unknown type"));
break;
case OBJ_COMMIT:
- if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) {
+ if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
}
free(buf);
- if ((c = lookup_commit_reference(sha1)) != NULL)
+ if ((c = lookup_commit_reference(oid->hash)) != NULL)
strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
break;
case OBJ_TREE:
struct strbuf buf = STRBUF_INIT;
struct strbuf ref = STRBUF_INIT;
struct strbuf reflog_msg = STRBUF_INIT;
- unsigned char object[20], prev[20];
+ struct object_id object, prev;
const char *object_ref, *tag;
struct create_tag_options opt;
char *cleanup_arg = NULL;
OPT_GROUP(N_("Tag listing options")),
OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
OPT_CONTAINS(&filter.with_commit, N_("print only tags that contain the commit")),
+ OPT_NO_CONTAINS(&filter.no_commit, N_("print only tags that don't contain the commit")),
OPT_WITH(&filter.with_commit, N_("print only tags that contain the commit")),
+ 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),
{
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
- N_("print only tags of the object"), 0, parse_opt_object_name
+ N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
+ parse_opt_object_name, (intptr_t) "HEAD"
},
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
}
create_tag_object = (opt.sign || annotate || msg.given || msgfile);
- if (argc == 0 && !cmdmode)
- cmdmode = 'l';
+ if (!cmdmode) {
+ if (argc == 0)
+ cmdmode = 'l';
+ else if (filter.with_commit || filter.no_commit ||
+ filter.points_at.nr || filter.merge_commit ||
+ filter.lines != -1)
+ cmdmode = 'l';
+ }
if ((create_tag_object || force) && (cmdmode != 0))
usage_with_options(git_tag_usage, options);
return ret;
}
if (filter.lines != -1)
- die(_("-n option is only allowed with -l."));
+ die(_("-n option is only allowed in list mode"));
if (filter.with_commit)
- die(_("--contains option is only allowed with -l."));
+ 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 with -l."));
+ die(_("--points-at option is only allowed in list mode"));
if (filter.merge_commit)
- die(_("--merged and --no-merged option are only allowed with -l"));
+ die(_("--merged and --no-merged options are only allowed in list mode"));
if (cmdmode == 'd')
return for_each_tag_name(argv, delete_tag, NULL);
if (cmdmode == 'v') {
if (argc > 2)
die(_("too many params"));
- if (get_sha1(object_ref, object))
+ if (get_oid(object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
if (strbuf_check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
- if (read_ref(ref.buf, prev))
- hashclr(prev);
+ if (read_ref(ref.buf, prev.hash))
+ oidclr(&prev);
else if (!force)
die(_("tag '%s' already exists"), tag);
else
die(_("Invalid cleanup mode %s"), cleanup_arg);
- create_reflog_msg(object, &reflog_msg);
+ create_reflog_msg(&object, &reflog_msg);
if (create_tag_object) {
if (force_sign_annotate && !annotate)
opt.sign = 1;
- create_tag(object, tag, &buf, &opt, prev, object);
+ create_tag(&object, tag, &buf, &opt, &prev, &object);
}
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, object, prev,
+ ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
- if (force && !is_null_sha1(prev) && hashcmp(prev, object))
- printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
+ if (force && !is_null_oid(&prev) && oidcmp(&prev, &object))
+ printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV));
strbuf_release(&err);
strbuf_release(&buf);