Skip to content

Commit d1645d0

Browse files
anderskgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3cfa4db commit d1645d0

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

builtin/describe.c

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static int longformat;
2424
static int abbrev = DEFAULT_ABBREV;
2525
static int max_candidates = 10;
2626
static struct hash_table names;
27+
static int have_util;
2728
static const char *pattern;
2829
static int always;
2930
static const char *dirty;
@@ -62,6 +63,17 @@ static inline struct commit_name *find_commit_name(const unsigned char *peeled)
6263
return n;
6364
}
6465

66+
static int set_util(void *chain)
67+
{
68+
struct commit_name *n;
69+
for (n = chain; n; n = n->next) {
70+
struct commit *c = lookup_commit_reference_gently(n->peeled, 1);
71+
if (c)
72+
c->util = n;
73+
}
74+
return 0;
75+
}
76+
6577
static int replace_name(struct commit_name *e,
6678
int prio,
6779
const unsigned char *sha1,
@@ -96,18 +108,16 @@ static int replace_name(struct commit_name *e,
96108
}
97109

98110
static void add_to_known_names(const char *path,
99-
struct commit *commit,
111+
const unsigned char *peeled,
100112
int prio,
101113
const unsigned char *sha1)
102114
{
103-
const unsigned char *peeled = commit->object.sha1;
104115
struct commit_name *e = find_commit_name(peeled);
105116
struct tag *tag = NULL;
106117
if (replace_name(e, prio, sha1, &tag)) {
107118
if (!e) {
108119
void **pos;
109120
e = xmalloc(sizeof(struct commit_name));
110-
commit->util = e;
111121
hashcpy(e->peeled, peeled);
112122
pos = insert_hash(hash_sha1(peeled), e, &names);
113123
if (pos) {
@@ -128,25 +138,17 @@ static void add_to_known_names(const char *path,
128138
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
129139
{
130140
int might_be_tag = !prefixcmp(path, "refs/tags/");
131-
struct commit *commit;
132-
struct object *object;
133141
unsigned char peeled[20];
134142
int is_tag, prio;
135143

136144
if (!all && !might_be_tag)
137145
return 0;
138146

139147
if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
140-
commit = lookup_commit_reference_gently(peeled, 1);
141-
if (!commit)
142-
return 0;
143-
is_tag = !!hashcmp(sha1, commit->object.sha1);
148+
is_tag = !!hashcmp(sha1, peeled);
144149
} else {
145-
commit = lookup_commit_reference_gently(sha1, 1);
146-
object = parse_object(sha1);
147-
if (!commit || !object)
148-
return 0;
149-
is_tag = object->type == OBJ_TAG;
150+
hashcpy(peeled, sha1);
151+
is_tag = 0;
150152
}
151153

152154
/* 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
169171
if (!prio)
170172
return 0;
171173
}
172-
add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1);
174+
add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
173175
return 0;
174176
}
175177

@@ -286,6 +288,11 @@ static void describe(const char *arg, int last_one)
286288
if (debug)
287289
fprintf(stderr, "searching to describe %s\n", arg);
288290

291+
if (!have_util) {
292+
for_each_hash(&names, set_util);
293+
have_util = 1;
294+
}
295+
289296
list = NULL;
290297
cmit->object.flags = SEEN;
291298
commit_list_insert(cmit, &list);

0 commit comments

Comments
 (0)