Skip to content

Commit

Permalink
describe: Delay looking up commits until searching for an inexact match
Browse files Browse the repository at this point in the history
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 <andersk@ksplice.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Anders Kaseorg authored and Junio C Hamano committed Dec 9, 2010
1 parent 3cfa4db commit d1645d0
Showing 1 changed file with 22 additions and 15 deletions.
37 changes: 22 additions & 15 deletions builtin/describe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -128,25 +138,17 @@ 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;

if (!all && !might_be_tag)
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.
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit d1645d0

Please sign in to comment.