From d1645d02defe43fa5b43140050ba265fcc49fa70 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 9 Dec 2010 01:47:29 -0500 Subject: [PATCH] describe: Delay looking up commits until searching for an inexact match Now that struct commit.util is not used until after we've checked that the argument doesn't exactly match a tag, we can wait until then to look up the commits for each tag. This avoids a lot of I/O on --exact-match queries in repositories with many tags. For example, 'git describe --exact-match HEAD' becomes about 12 times faster on a cold cache (3.2s instead of 39s) in a linux-2.6 repository with 2000 packed tags. That is a huge win for the interactivity of the __git_ps1 shell prompt helper when on a detached HEAD. Signed-off-by: Anders Kaseorg Signed-off-by: Junio C Hamano --- builtin/describe.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/builtin/describe.c b/builtin/describe.c index 8149233059..a0f52c1b72 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -24,6 +24,7 @@ static int longformat; static int abbrev = DEFAULT_ABBREV; static int max_candidates = 10; static struct hash_table names; +static int have_util; static const char *pattern; static int always; static const char *dirty; @@ -62,6 +63,17 @@ static inline struct commit_name *find_commit_name(const unsigned char *peeled) return n; } +static int set_util(void *chain) +{ + struct commit_name *n; + for (n = chain; n; n = n->next) { + struct commit *c = lookup_commit_reference_gently(n->peeled, 1); + if (c) + c->util = n; + } + return 0; +} + static int replace_name(struct commit_name *e, int prio, const unsigned char *sha1, @@ -96,18 +108,16 @@ 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) { - const unsigned char *peeled = commit->object.sha1; struct commit_name *e = find_commit_name(peeled); struct tag *tag = NULL; if (replace_name(e, prio, sha1, &tag)) { if (!e) { void **pos; e = xmalloc(sizeof(struct commit_name)); - commit->util = e; hashcpy(e->peeled, peeled); pos = insert_hash(hash_sha1(peeled), e, &names); if (pos) { @@ -128,8 +138,6 @@ static void add_to_known_names(const char *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/"); - struct commit *commit; - struct object *object; unsigned char peeled[20]; int is_tag, prio; @@ -137,16 +145,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. @@ -169,7 +171,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; } @@ -286,6 +288,11 @@ static void describe(const char *arg, int last_one) if (debug) fprintf(stderr, "searching to describe %s\n", arg); + if (!have_util) { + for_each_hash(&names, set_util); + have_util = 1; + } + list = NULL; cmit->object.flags = SEEN; commit_list_insert(cmit, &list); -- 2.11.4.GIT