Skip to content

Commit d7c1ec3

Browse files
derrickstoleegitster
authored andcommitted
commit: add short-circuit to paint_down_to_common()
When running 'git branch --contains', the in_merge_bases_many() method calls paint_down_to_common() to discover if a specific commit is reachable from a set of branches. Commits with lower generation number are not needed to correctly answer the containment query of in_merge_bases_many(). Add a new parameter, min_generation, to paint_down_to_common() that prevents walking commits with generation number strictly less than min_generation. If 0 is given, then there is no functional change. For in_merge_bases_many(), we can pass commit->generation as the cutoff, and this saves time during 'git branch --contains' queries that would otherwise walk "around" the commit we are inspecting. For a copy of the Linux repository, where HEAD is checked out at v4.13~100, we get the following performance improvement for 'git branch --contains' over the previous commit: Before: 0.21s After: 0.13s Rel %: -38% Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f9b8908 commit d7c1ec3

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

commit.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -808,11 +808,14 @@ static int queue_has_nonstale(struct prio_queue *queue)
808808
}
809809

810810
/* all input commits in one and twos[] must have been parsed! */
811-
static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
811+
static struct commit_list *paint_down_to_common(struct commit *one, int n,
812+
struct commit **twos,
813+
int min_generation)
812814
{
813815
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
814816
struct commit_list *result = NULL;
815817
int i;
818+
uint32_t last_gen = GENERATION_NUMBER_INFINITY;
816819

817820
one->object.flags |= PARENT1;
818821
if (!n) {
@@ -831,6 +834,15 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
831834
struct commit_list *parents;
832835
int flags;
833836

837+
if (commit->generation > last_gen)
838+
BUG("bad generation skip %8x > %8x at %s",
839+
commit->generation, last_gen,
840+
oid_to_hex(&commit->object.oid));
841+
last_gen = commit->generation;
842+
843+
if (commit->generation < min_generation)
844+
break;
845+
834846
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
835847
if (flags == (PARENT1 | PARENT2)) {
836848
if (!(commit->object.flags & RESULT)) {
@@ -879,7 +891,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
879891
return NULL;
880892
}
881893

882-
list = paint_down_to_common(one, n, twos);
894+
list = paint_down_to_common(one, n, twos, 0);
883895

884896
while (list) {
885897
struct commit *commit = pop_commit(&list);
@@ -946,7 +958,7 @@ static int remove_redundant(struct commit **array, int cnt)
946958
filled_index[filled] = j;
947959
work[filled++] = array[j];
948960
}
949-
common = paint_down_to_common(array[i], filled, work);
961+
common = paint_down_to_common(array[i], filled, work, 0);
950962
if (array[i]->object.flags & PARENT2)
951963
redundant[i] = 1;
952964
for (j = 0; j < filled; j++)
@@ -1070,7 +1082,7 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
10701082
if (commit->generation > min_generation)
10711083
return ret;
10721084

1073-
bases = paint_down_to_common(commit, nr_reference, reference);
1085+
bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
10741086
if (commit->object.flags & PARENT2)
10751087
ret = 1;
10761088
clear_commit_marks(commit, all_flags);

0 commit comments

Comments
 (0)