From e6e4a47ba12bd19ed956251f191b1ea9915f61f8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Jul 2009 10:17:04 -0700 Subject: git branch: fix performance problem 'git branch' looks at _all_ the refs, and verifies them. Which means that during cold-cache situations with a slow disk (and lots of tags, for example) it can take several very annoying seconds (7.5s according to a report by Carlos R. Mafra). This avoids most of it by simply doing the filtering before looking up the commits, by using the "raw" version of for_each_ref. Reported-by: Carlos R. Mafra Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-branch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'builtin-branch.c') diff --git a/builtin-branch.c b/builtin-branch.c index 91098ca9b1..3784dda090 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -240,6 +240,10 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if (ARRAY_SIZE(ref_kind) <= i) return 0; + /* Don't add types the caller doesn't want */ + if ((kind & ref_list->kinds) == 0) + return 0; + commit = lookup_commit_reference_gently(sha1, 1); if (!commit) return error("branch '%s' does not point at a commit", refname); @@ -248,10 +252,6 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if (!is_descendant_of(commit, ref_list->with_commit)) return 0; - /* Don't add types the caller doesn't want */ - if ((kind & ref_list->kinds) == 0) - return 0; - if (merge_filter != NO_FILTER) add_pending_object(&ref_list->revs, (struct object *)commit, refname); @@ -426,7 +426,7 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); - for_each_ref(append_ref, &ref_list); + for_each_rawref(append_ref, &ref_list); if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); -- cgit v1.2.1 From 191d1ac435c01e2a7acfb93fb9da8378da90214c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Jul 2009 12:05:34 -0700 Subject: git branch: avoid unnecessary object lookups They can be expensive in the cold-cache case, so don't bother looking up the commits for all branches unless we really need them for some reason. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-branch.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'builtin-branch.c') diff --git a/builtin-branch.c b/builtin-branch.c index 3784dda090..0e30756b1b 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -191,7 +191,7 @@ struct ref_item { struct ref_list { struct rev_info revs; - int index, alloc, maxwidth; + int index, alloc, maxwidth, verbose; struct ref_item *list; struct commit_list *with_commit; int kinds; @@ -244,17 +244,20 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if ((kind & ref_list->kinds) == 0) return 0; - commit = lookup_commit_reference_gently(sha1, 1); - if (!commit) - return error("branch '%s' does not point at a commit", refname); + commit = NULL; + if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) { + commit = lookup_commit_reference_gently(sha1, 1); + if (!commit) + return error("branch '%s' does not point at a commit", refname); - /* Filter with with_commit if specified */ - if (!is_descendant_of(commit, ref_list->with_commit)) - return 0; + /* Filter with with_commit if specified */ + if (!is_descendant_of(commit, ref_list->with_commit)) + return 0; - if (merge_filter != NO_FILTER) - add_pending_object(&ref_list->revs, - (struct object *)commit, refname); + if (merge_filter != NO_FILTER) + add_pending_object(&ref_list->revs, + (struct object *)commit, refname); + } /* Resize buffer */ if (ref_list->index >= ref_list->alloc) { @@ -423,6 +426,7 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; + ref_list.verbose = verbose; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); -- cgit v1.2.1 From 7e9ff00bbe1f437ff492a714758a4f7360feb22b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Jul 2009 12:13:48 -0700 Subject: git branch: clean up detached branch handling Make the 'show detached branch info' a routine of its own. And in the process, avoid the object lookup that is unnecessary if the current branch isn't detached. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-branch.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'builtin-branch.c') diff --git a/builtin-branch.c b/builtin-branch.c index 0e30756b1b..887fa60fa5 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -191,7 +191,7 @@ struct ref_item { struct ref_list { struct rev_info revs; - int index, alloc, maxwidth, verbose; + int index, alloc, maxwidth, verbose, abbrev; struct ref_item *list; struct commit_list *with_commit; int kinds; @@ -418,15 +418,34 @@ static int calc_maxwidth(struct ref_list *refs) return w; } + +static void show_detached(struct ref_list *ref_list) +{ + struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); + + if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) { + struct ref_item item; + item.name = xstrdup("(no branch)"); + item.len = strlen(item.name); + item.kind = REF_LOCAL_BRANCH; + item.dest = NULL; + item.commit = head_commit; + if (item.len > ref_list->maxwidth) + ref_list->maxwidth = item.len; + print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, ""); + free(item.name); + } +} + static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit) { int i; struct ref_list ref_list; - struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; ref_list.verbose = verbose; + ref_list.abbrev = abbrev; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); @@ -446,19 +465,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); detached = (detached && (kinds & REF_LOCAL_BRANCH)); - if (detached && head_commit && - is_descendant_of(head_commit, with_commit)) { - struct ref_item item; - item.name = xstrdup("(no branch)"); - item.len = strlen(item.name); - item.kind = REF_LOCAL_BRANCH; - item.dest = NULL; - item.commit = head_commit; - if (item.len > ref_list.maxwidth) - ref_list.maxwidth = item.len; - print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, ""); - free(item.name); - } + if (detached) + show_detached(&ref_list); for (i = 0; i < ref_list.index; i++) { int current = !detached && -- cgit v1.2.1