If the user asks to display (or sort by) the %(HEAD) atom, ref-filter has to compare each refname to the value of HEAD. We do so by resolving HEAD fresh when calling populate_value() on each ref. If there are a large number of refs, this can have a measurable impact on runtime. Instead, let's resolve HEAD once when we realize we need the %(HEAD) atom, allowing us to do a simple string comparison for each ref. On a repository with 3000 branches (high, but an actual example found in the wild) this drops the best-of-five time to run "git branch >/dev/null" from 59ms to 48ms (~20% savings). Signed-off-by: Jeff King <peff@xxxxxxxx> --- The "something like this" patch I sent earlier just cached the value of HEAD in a global for the length of the program. This is a bit nicer, in that it ties the cache to the atom we are filling in. But since that's also stored in a program global, the end effect is the same. :) I think it's still worth doing it this way, though, as we might one day push the used_atom stuff into some kind of ref_filter_context struct, and then this would Just Work. I did take a look at de-globalifying used_atom and friends, but it gets pretty nasty pushing it all through the callstack. Since there's no immediate benefit, I don't think it's really worth pursuing for now. ref-filter.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ref-filter.c b/ref-filter.c index 1fc5e9970..82ca411d0 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -93,6 +93,7 @@ static struct used_atom { unsigned int length; } objectname; struct refname_atom refname; + char *head; } u; } *used_atom; static int used_atom_cnt, need_tagged, need_symref; @@ -287,6 +288,12 @@ static void if_atom_parser(struct used_atom *atom, const char *arg) } } +static void head_atom_parser(struct used_atom *atom, const char *arg) +{ + unsigned char unused[GIT_SHA1_RAWSZ]; + + atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, unused, NULL); +} static struct { const char *name; @@ -325,7 +332,7 @@ static struct { { "push", FIELD_STR, remote_ref_atom_parser }, { "symref", FIELD_STR, refname_atom_parser }, { "flag" }, - { "HEAD" }, + { "HEAD", FIELD_STR, head_atom_parser }, { "color", FIELD_STR, color_atom_parser }, { "align", FIELD_STR, align_atom_parser }, { "end" }, @@ -1369,12 +1376,7 @@ static void populate_value(struct ref_array_item *ref) } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) { continue; } else if (!strcmp(name, "HEAD")) { - const char *head; - unsigned char sha1[20]; - - head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, - sha1, NULL); - if (head && !strcmp(ref->refname, head)) + if (atom->u.head && !strcmp(ref->refname, atom->u.head)) v->s = "*"; else v->s = " "; -- 2.13.0.219.g63f6bc368