From: Junio C Hamano Date: Mon, 20 Feb 2012 08:15:28 +0000 (-0800) Subject: Merge branch 'tg/tag-points-at' X-Git-Tag: v1.7.10-rc0~68 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/76bdcf0ee31afc020df104a4997ffae2a72ca302?hp=-c Merge branch 'tg/tag-points-at' * tg/tag-points-at: builtin/tag.c: Fix a sparse warning tag: add --points-at list option --- 76bdcf0ee31afc020df104a4997ffae2a72ca302 diff --combined builtin/tag.c index 03df16ac6e,e377706e6d..fe7e5e5b3d --- a/builtin/tag.c +++ b/builtin/tag.c @@@ -15,11 -15,13 +15,13 @@@ #include "diff.h" #include "revision.h" #include "gpg-interface.h" + #include "sha1-array.h" static const char * const git_tag_usage[] = { "git tag [-a|-s|-u ] [-f] [-m |-F ] []", "git tag -d ...", - "git tag -l [-n[]] [...]", + "git tag -l [-n[]] [--contains ] [--points-at ] " + "\n\t\t[...]", "git tag -v ...", NULL }; @@@ -30,6 -32,8 +32,8 @@@ struct tag_filter struct commit_list *with_commit; }; + static struct sha1_array points_at; + static int match_pattern(const char **patterns, const char *ref) { /* no pattern means match everything */ @@@ -41,6 -45,24 +45,24 @@@ return 0; } + static const unsigned char *match_points_at(const char *refname, + const unsigned char *sha1) + { + const unsigned char *tagged_sha1 = NULL; + struct object *obj; + + if (sha1_array_lookup(&points_at, sha1) >= 0) + return sha1; + obj = parse_object(sha1); + if (!obj) + die(_("malformed object at '%s'"), refname); + if (obj->type == OBJ_TAG) + tagged_sha1 = ((struct tag *)obj)->tagged->sha1; + if (tagged_sha1 && sha1_array_lookup(&points_at, tagged_sha1) >= 0) + return tagged_sha1; + return NULL; + } + static int in_commit_list(const struct commit_list *want, struct commit *c) { for (; want; want = want->next) @@@ -83,51 -105,18 +105,51 @@@ static int contains(struct commit *cand return contains_recurse(candidate, want); } +static void show_tag_lines(const unsigned char *sha1, int lines) +{ + int i; + unsigned long size; + enum object_type type; + char *buf, *sp, *eol; + size_t len; + + buf = read_sha1_file(sha1, &type, &size); + if (!buf) + die_errno("unable to read object %s", sha1_to_hex(sha1)); + if (type != OBJ_COMMIT && type != OBJ_TAG) + goto free_return; + if (!size) + die("an empty %s object %s?", + typename(type), sha1_to_hex(sha1)); + + /* skip header */ + sp = strstr(buf, "\n\n"); + if (!sp) + goto free_return; + + /* only take up to "lines" lines, and strip the signature from a tag */ + if (type == OBJ_TAG) + size = parse_signature(buf, size); + for (i = 0, sp += 2; i < lines && sp < buf + size; i++) { + if (i) + printf("\n "); + eol = memchr(sp, '\n', size - (sp - buf)); + len = eol ? eol - sp : size - (sp - buf); + fwrite(sp, len, 1, stdout); + if (!eol) + break; + sp = eol + 1; + } +free_return: + free(buf); +} + static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct tag_filter *filter = cb_data; if (match_pattern(filter->patterns, refname)) { - int i; - unsigned long size; - enum object_type type; - char *buf, *sp, *eol; - size_t len; - if (filter->with_commit) { struct commit *commit; @@@ -138,13 -127,41 +160,16 @@@ return 0; } + if (points_at.nr && !match_points_at(refname, sha1)) + return 0; + if (!filter->lines) { printf("%s\n", refname); return 0; } printf("%-15s ", refname); - - buf = read_sha1_file(sha1, &type, &size); - if (!buf || !size) - return 0; - - /* skip header */ - sp = strstr(buf, "\n\n"); - if (!sp) { - free(buf); - return 0; - } - /* only take up to "lines" lines, and strip the signature */ - size = parse_signature(buf, size); - for (i = 0, sp += 2; - i < filter->lines && sp < buf + size; - i++) { - if (i) - printf("\n "); - eol = memchr(sp, '\n', size - (sp - buf)); - len = eol ? eol - sp : size - (sp - buf); - fwrite(sp, len, 1, stdout); - if (!eol) - break; - sp = eol + 1; - } + show_tag_lines(sha1, filter->lines); putchar('\n'); - free(buf); } return 0; @@@ -383,6 -400,23 +408,23 @@@ static int strbuf_check_tag_ref(struct return check_refname_format(sb->buf, 0); } + static int parse_opt_points_at(const struct option *opt __attribute__((unused)), + const char *arg, int unset) + { + unsigned char sha1[20]; + + if (unset) { + sha1_array_clear(&points_at); + return 0; + } + if (!arg) + return error(_("switch 'points-at' requires an object")); + if (get_sha1(arg, sha1)) + return error(_("malformed object name '%s'"), arg); + sha1_array_append(&points_at, sha1); + return 0; + } + int cmd_tag(int argc, const char **argv, const char *prefix) { struct strbuf buf = STRBUF_INIT; @@@ -425,6 -459,10 +467,10 @@@ PARSE_OPT_LASTARG_DEFAULT, parse_opt_with_commit, (intptr_t)"HEAD", }, + { + OPTION_CALLBACK, 0, "points-at", NULL, "object", + "print only tags of the object", 0, parse_opt_points_at + }, OPT_END() }; @@@ -456,6 -494,8 +502,8 @@@ die(_("-n option is only allowed with -l.")); if (with_commit) die(_("--contains option is only allowed with -l.")); + if (points_at.nr) + die(_("--points-at option is only allowed with -l.")); if (delete) return for_each_tag_name(argv, delete_tag); if (verify) diff --combined t/t7004-tag.sh index 4ef79aabc4,f61e3987ee..f8c247a750 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@@ -586,19 -586,6 +586,19 @@@ test_expect_success test_cmp expect actual ' +test_expect_success 'annotations for blobs are empty' ' + blob=$(git hash-object -w --stdin <<-\EOF + Blob paragraph 1. + + Blob paragraph 2. + EOF + ) && + git tag tag-blob $blob && + echo "tag-blob " >expect && + git tag -n1 -l tag-blob >actual && + test_cmp expect actual +' + # trying to verify annotated non-signed tags: test_expect_success GPG \ @@@ -1282,4 -1269,43 +1282,43 @@@ test_expect_success 'mixing incompatibl test_must_fail git tag -v -s ' + # check points-at + + test_expect_success '--points-at cannot be used in non-list mode' ' + test_must_fail git tag --points-at=v4.0 foo + ' + + test_expect_success '--points-at finds lightweight tags' ' + echo v4.0 >expect && + git tag --points-at v4.0 >actual && + test_cmp expect actual + ' + + test_expect_success '--points-at finds annotated tags of commits' ' + git tag -m "v4.0, annotated" annotated-v4.0 v4.0 && + echo annotated-v4.0 >expect && + git tag -l --points-at v4.0 "annotated*" >actual && + test_cmp expect actual + ' + + test_expect_success '--points-at finds annotated tags of tags' ' + git tag -m "describing the v4.0 tag object" \ + annotated-again-v4.0 annotated-v4.0 && + cat >expect <<-\EOF && + annotated-again-v4.0 + annotated-v4.0 + EOF + git tag --points-at=annotated-v4.0 >actual && + test_cmp expect actual + ' + + test_expect_success 'multiple --points-at are OR-ed together' ' + cat >expect <<-\EOF && + v2.0 + v3.0 + EOF + git tag --points-at=v2.0 --points-at=v3.0 >actual && + test_cmp expect actual + ' + test_done