diff options
Diffstat (limited to 'builtin/describe.c')
-rw-r--r-- | builtin/describe.c | 56 |
1 files changed, 31 insertions, 25 deletions
diff --git a/builtin/describe.c b/builtin/describe.c index 04c185b1fb..4e675c3d0d 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -21,6 +21,7 @@ static int debug; /* Display lots of verbose info */ static int all; /* Any valid ref can be used */ static int tags; /* Allow lightweight tags */ static int longformat; +static int first_parent; static int abbrev = -1; /* unspecified */ static int max_candidates = 10; static struct hash_table names; @@ -42,7 +43,7 @@ struct commit_name { unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */ unsigned name_checked:1; unsigned char sha1[20]; - const char *path; + char *path; }; static const char *prio_names[] = { "head", "lightweight", "annotated", @@ -126,51 +127,52 @@ static void add_to_known_names(const char *path, } else { e->next = NULL; } + e->path = NULL; } e->tag = tag; e->prio = prio; e->name_checked = 0; hashcpy(e->sha1, sha1); - e->path = path; + free(e->path); + e->path = xstrdup(path); } } static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data) { - int might_be_tag = !prefixcmp(path, "refs/tags/"); + int is_tag = !prefixcmp(path, "refs/tags/"); unsigned char peeled[20]; - int is_tag, prio; + int is_annotated, prio; - if (!all && !might_be_tag) + /* Reject anything outside refs/tags/ unless --all */ + if (!all && !is_tag) return 0; + /* Accept only tags that match the pattern, if given */ + if (pattern && (!is_tag || fnmatch(pattern, path + 10, 0))) + return 0; + + /* Is it annotated? */ if (!peel_ref(path, peeled)) { - is_tag = !!hashcmp(sha1, peeled); + is_annotated = !!hashcmp(sha1, peeled); } else { hashcpy(peeled, sha1); - is_tag = 0; + is_annotated = 0; } - /* If --all, then any refs are used. - * If --tags, then any tags are used. - * Otherwise only annotated tags are used. + /* + * By default, we only use annotated tags, but with --tags + * we fall back to lightweight ones (even without --tags, + * we still remember lightweight ones, only to give hints + * in an error message). --all allows any refs to be used. */ - if (might_be_tag) { - if (is_tag) - prio = 2; - else - prio = 1; - - if (pattern && fnmatch(pattern, path + 10, 0)) - prio = 0; - } + if (is_annotated) + prio = 2; + else if (is_tag) + prio = 1; else prio = 0; - if (!all) { - if (!prio) - return 0; - } add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1); return 0; } @@ -337,6 +339,9 @@ static void describe(const char *arg, int last_one) commit_list_insert_by_date(p, &list); p->object.flags |= c->object.flags; parents = parents->next; + + if (first_parent) + break; } } @@ -402,9 +407,10 @@ int cmd_describe(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_BOOLEAN(0, "contains", &contains, N_("find the tag that comes after the commit")), OPT_BOOLEAN(0, "debug", &debug, N_("debug search strategy on stderr")), - OPT_BOOLEAN(0, "all", &all, N_("use any ref in .git/refs")), - OPT_BOOLEAN(0, "tags", &tags, N_("use any tag in .git/refs/tags")), + OPT_BOOLEAN(0, "all", &all, N_("use any ref")), + OPT_BOOLEAN(0, "tags", &tags, N_("use any tag, even unannotated")), OPT_BOOLEAN(0, "long", &longformat, N_("always use long format")), + OPT_BOOLEAN(0, "first-parent", &first_parent, N_("only follow first parent")), OPT__ABBREV(&abbrev), OPT_SET_INT(0, "exact-match", &max_candidates, N_("only output exact matches"), 0), |