This makes âgit describe --exact-match HEADâ about 15 times faster on a cold cache (2.3s instead of 35s) in a linux-2.6 repository with many packed tags. Thatâs a huge win for the interactivity of the __git_ps1 shell prompt helper when on a detached head. Signed-off-by: Anders Kaseorg <andersk@xxxxxxxxxxx> diff --git a/builtin/describe.c b/builtin/describe.c index 700f740..0cddef1 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -22,7 +22,7 @@ static int tags; /* Allow lightweight tags */ static int longformat; static int abbrev = DEFAULT_ABBREV; static int max_candidates = 10; -static int found_names; +static struct commit_name *names; static const char *pattern; static int always; static const char *dirty; @@ -34,6 +34,8 @@ static const char *diff_index_args[] = { struct commit_name { + struct commit_name *next; + unsigned char peeled[20]; struct tag *tag; unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */ unsigned name_checked:1; @@ -78,31 +80,26 @@ static int replace_name(struct commit_name *e, } static void add_to_known_names(const char *path, - struct commit *commit, + const unsigned char *peeled, int prio, const unsigned char *sha1) { - struct commit_name *e = commit->util; struct tag *tag = NULL; - if (replace_name(e, prio, sha1, &tag)) { - size_t len = strlen(path)+1; - free(e); - e = xmalloc(sizeof(struct commit_name) + len); - e->tag = tag; - e->prio = prio; - e->name_checked = 0; - hashcpy(e->sha1, sha1); - memcpy(e->path, path, len); - commit->util = e; - } - found_names = 1; + size_t len = strlen(path)+1; + struct commit_name *e = xmalloc(sizeof(struct commit_name) + len); + hashcpy(e->peeled, peeled); + e->tag = tag; + e->prio = prio; + e->name_checked = 0; + hashcpy(e->sha1, sha1); + memcpy(e->path, path, len); + e->next = names; + names = e; } static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data) { int might_be_tag = !prefixcmp(path, "refs/tags/"); - struct commit *commit; - struct object *object; unsigned char peeled[20]; int is_tag, prio; @@ -110,16 +107,10 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void return 0; if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) { - commit = lookup_commit_reference_gently(peeled, 1); - if (!commit) - return 0; - is_tag = !!hashcmp(sha1, commit->object.sha1); + is_tag = !!hashcmp(sha1, peeled); } else { - commit = lookup_commit_reference_gently(sha1, 1); - object = parse_object(sha1); - if (!commit || !object) - return 0; - is_tag = object->type == OBJ_TAG; + hashcpy(peeled, sha1); + is_tag = 0; } /* If --all, then any refs are used. @@ -142,7 +133,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void if (!prio) return 0; } - add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1); + add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1); return 0; } @@ -228,7 +219,7 @@ static void describe(const char *arg, int last_one) unsigned char sha1[20]; struct commit *cmit, *gave_up_on = NULL; struct commit_list *list; - struct commit_name *n; + struct commit_name *n, *e; struct possible_tag all_matches[MAX_TAGS]; unsigned int match_cnt = 0, annotated_cnt = 0, cur_match; unsigned long seen_commits = 0; @@ -240,7 +231,12 @@ static void describe(const char *arg, int last_one) if (!cmit) die("%s is not a valid '%s' object", arg, commit_type); - n = cmit->util; + n = NULL; + for (e = names; e; e = e->next) { + if (!hashcmp(e->peeled, cmit->object.sha1) && + replace_name(n, e->prio, e->sha1, &e->tag)) + n = e; + } if (n && (tags || all || n->prio == 2)) { /* * Exact match to an existing ref. @@ -259,6 +255,12 @@ static void describe(const char *arg, int last_one) if (debug) fprintf(stderr, "searching to describe %s\n", arg); + for (e = names; e; e = e->next) { + struct commit *c = lookup_commit_reference_gently(e->peeled, 1); + if (c && replace_name(c->util, e->prio, e->sha1, &e->tag)) + c->util = e; + } + list = NULL; cmit->object.flags = SEEN; commit_list_insert(cmit, &list); @@ -419,7 +421,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) } for_each_rawref(get_name, NULL); - if (!found_names && !always) + if (!names && !always) die("No names found, cannot describe anything."); if (argc == 0) { -- 1.7.3.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html