get_merge_bases_many(): walk from many tips in parallel
The get_merge_bases_many() function reduces the result returned by the merge_bases_many() function, which is a set of possible merge bases, by excluding commits that can be reached from other commits. We used to do N*(N-1) traversals for this, but we can check if one commit reaches which other (N-1) commits by a single traversal, and repeat it for all the candidates to find the answer. Introduce remove_redundant() helper function to do this painting; we should be able to use it to reimplement reduce_heads() as well. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
6440fdbab4
commit
94f0ced0d0
79
commit.c
79
commit.c
@ -692,6 +692,60 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int remove_redundant(struct commit **array, int cnt)
|
||||
{
|
||||
/*
|
||||
* Some commit in the array may be an ancestor of
|
||||
* another commit. Move such commit to the end of
|
||||
* the array, and return the number of commits that
|
||||
* are independent from each other.
|
||||
*/
|
||||
struct commit **work;
|
||||
unsigned char *redundant;
|
||||
int *filled_index;
|
||||
int i, j, filled;
|
||||
|
||||
work = xcalloc(cnt, sizeof(*work));
|
||||
redundant = xcalloc(cnt, 1);
|
||||
filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct commit_list *common;
|
||||
|
||||
if (redundant[i])
|
||||
continue;
|
||||
for (j = filled = 0; j < cnt; j++) {
|
||||
if (i == j || redundant[j])
|
||||
continue;
|
||||
filled_index[filled] = j;
|
||||
work[filled++] = array[j];
|
||||
}
|
||||
common = paint_down_to_common(array[i], filled, work);
|
||||
if (array[i]->object.flags & PARENT2)
|
||||
redundant[i] = 1;
|
||||
for (j = 0; j < filled; j++)
|
||||
if (work[j]->object.flags & PARENT1)
|
||||
redundant[filled_index[j]] = 1;
|
||||
clear_commit_marks(array[i], all_flags);
|
||||
for (j = 0; j < filled; j++)
|
||||
clear_commit_marks(work[j], all_flags);
|
||||
free_commit_list(common);
|
||||
}
|
||||
|
||||
/* Now collect the result */
|
||||
memcpy(work, array, sizeof(*array) * cnt);
|
||||
for (i = filled = 0; i < cnt; i++)
|
||||
if (!redundant[i])
|
||||
array[filled++] = work[i];
|
||||
for (j = filled, i = 0; i < cnt; i++)
|
||||
if (redundant[i])
|
||||
array[j++] = work[i];
|
||||
free(work);
|
||||
free(redundant);
|
||||
free(filled_index);
|
||||
return filled;
|
||||
}
|
||||
|
||||
struct commit_list *get_merge_bases_many(struct commit *one,
|
||||
int n,
|
||||
struct commit **twos,
|
||||
@ -700,7 +754,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
|
||||
struct commit_list *list;
|
||||
struct commit **rslt;
|
||||
struct commit_list *result;
|
||||
int cnt, i, j;
|
||||
int cnt, i;
|
||||
|
||||
result = merge_bases_many(one, n, twos);
|
||||
for (i = 0; i < n; i++) {
|
||||
@ -731,28 +785,11 @@ struct commit_list *get_merge_bases_many(struct commit *one,
|
||||
clear_commit_marks(one, all_flags);
|
||||
for (i = 0; i < n; i++)
|
||||
clear_commit_marks(twos[i], all_flags);
|
||||
for (i = 0; i < cnt - 1; i++) {
|
||||
for (j = i+1; j < cnt; j++) {
|
||||
if (!rslt[i] || !rslt[j])
|
||||
continue;
|
||||
result = merge_bases_many(rslt[i], 1, &rslt[j]);
|
||||
clear_commit_marks(rslt[i], all_flags);
|
||||
clear_commit_marks(rslt[j], all_flags);
|
||||
for (list = result; list; list = list->next) {
|
||||
if (rslt[i] == list->item)
|
||||
rslt[i] = NULL;
|
||||
if (rslt[j] == list->item)
|
||||
rslt[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Surviving ones in rslt[] are the independent results */
|
||||
cnt = remove_redundant(rslt, cnt);
|
||||
result = NULL;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (rslt[i])
|
||||
commit_list_insert_by_date(rslt[i], &result);
|
||||
}
|
||||
for (i = 0; i < cnt; i++)
|
||||
commit_list_insert_by_date(rslt[i], &result);
|
||||
free(rslt);
|
||||
return result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user