Skip to content

Commit f37d3c7

Browse files
committed
reduce_heads(): reimplement on top of remove_redundant()
This is used by "git merge" and "git merge-base --independent" but used to use a similar N*(N-1) traversals to reject commits that are ancestors of other commits. Reimplement it on top of remove_redundant(). Note that the callers of this function are allowed to pass the same commit more than once, but remove_redundant() is designed to be fed each commit only once. The function removes duplicates before calling remove_redundant(). Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5907cda commit f37d3c7

File tree

1 file changed

+18
-38
lines changed

1 file changed

+18
-38
lines changed

commit.c

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -842,51 +842,31 @@ struct commit_list *reduce_heads(struct commit_list *heads)
842842
{
843843
struct commit_list *p;
844844
struct commit_list *result = NULL, **tail = &result;
845-
struct commit **other;
846-
size_t num_head, num_other;
845+
struct commit **array;
846+
int num_head, i;
847847

848848
if (!heads)
849849
return NULL;
850850

851-
/* Avoid unnecessary reallocations */
852-
for (p = heads, num_head = 0; p; p = p->next)
853-
num_head++;
854-
other = xcalloc(sizeof(*other), num_head);
855-
856-
/* For each commit, see if it can be reached by others */
857-
for (p = heads; p; p = p->next) {
858-
struct commit_list *q, *base;
859-
860-
/* Do we already have this in the result? */
861-
for (q = result; q; q = q->next)
862-
if (p->item == q->item)
863-
break;
864-
if (q)
851+
/* Uniquify */
852+
for (p = heads; p; p = p->next)
853+
p->item->object.flags &= ~STALE;
854+
for (p = heads, num_head = 0; p; p = p->next) {
855+
if (p->item->object.flags & STALE)
865856
continue;
866-
867-
num_other = 0;
868-
for (q = heads; q; q = q->next) {
869-
if (p->item == q->item)
870-
continue;
871-
other[num_other++] = q->item;
857+
p->item->object.flags |= STALE;
858+
num_head++;
859+
}
860+
array = xcalloc(sizeof(*array), num_head);
861+
for (p = heads, i = 0; p; p = p->next) {
862+
if (p->item->object.flags & STALE) {
863+
array[i++] = p->item;
864+
p->item->object.flags &= ~STALE;
872865
}
873-
if (num_other)
874-
base = get_merge_bases_many(p->item, num_other, other, 1);
875-
else
876-
base = NULL;
877-
/*
878-
* If p->item does not have anything common with other
879-
* commits, there won't be any merge base. If it is
880-
* reachable from some of the others, p->item will be
881-
* the merge base. If its history is connected with
882-
* others, but p->item is not reachable by others, we
883-
* will get something other than p->item back.
884-
*/
885-
if (!base || (base->item != p->item))
886-
tail = &(commit_list_insert(p->item, tail)->next);
887-
free_commit_list(base);
888866
}
889-
free(other);
867+
num_head = remove_redundant(array, num_head);
868+
for (i = 0; i < num_head; i++)
869+
tail = &commit_list_insert(array[i], tail)->next;
890870
return result;
891871
}
892872

0 commit comments

Comments
 (0)