summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--commit-reach.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/commit-reach.c b/commit-reach.c
index a34c5ba09e..399f2a8673 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -29,6 +29,10 @@ static int compare_commits_by_gen(const void *_a, const void *_b)
return -1;
if (generation_a > generation_b)
return 1;
+ if (a->date < b->date)
+ return -1;
+ if (a->date > b->date)
+ return 1;
return 0;
}
@@ -228,11 +232,10 @@ static int remove_redundant_no_gen(struct repository *r,
static int remove_redundant_with_gen(struct repository *r,
struct commit **array, int cnt)
{
- int i, count_non_stale = 0;
+ int i, count_non_stale = 0, count_still_independent = cnt;
timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
struct commit **walk_start;
size_t walk_start_nr = 0, walk_start_alloc = cnt;
- struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
ALLOC_ARRAY(walk_start, walk_start_alloc);
@@ -242,6 +245,7 @@ static int remove_redundant_with_gen(struct repository *r,
timestamp_t generation;
repo_parse_commit(r, array[i]);
+ array[i]->object.flags |= RESULT;
parents = array[i]->parents;
while (parents) {
@@ -250,7 +254,6 @@ static int remove_redundant_with_gen(struct repository *r,
parents->item->object.flags |= STALE;
ALLOC_GROW(walk_start, walk_start_nr + 1, walk_start_alloc);
walk_start[walk_start_nr++] = parents->item;
- prio_queue_put(&queue, parents->item);
}
parents = parents->next;
}
@@ -261,26 +264,63 @@ static int remove_redundant_with_gen(struct repository *r,
min_generation = generation;
}
- /* push the STALE bits up to min generation */
- while (queue.nr) {
- struct commit_list *parents;
- struct commit *c = prio_queue_get(&queue);
+ QSORT(walk_start, walk_start_nr, compare_commits_by_gen);
- repo_parse_commit(r, c);
+ /* remove STALE bit for now to allow walking through parents */
+ for (i = 0; i < walk_start_nr; i++)
+ walk_start[i]->object.flags &= ~STALE;
- if (commit_graph_generation(c) < min_generation)
- continue;
+ /*
+ * Start walking from the highest generation. Hopefully, it will
+ * find all other items during the first-parent walk, and we can
+ * terminate early. Otherwise, we will do the same amount of work
+ * as before.
+ */
+ for (i = walk_start_nr - 1; i >= 0 && count_still_independent > 1; i--) {
+ /* push the STALE bits up to min generation */
+ struct commit_list *stack = NULL;
- parents = c->parents;
- while (parents) {
- if (!(parents->item->object.flags & STALE)) {
- parents->item->object.flags |= STALE;
- prio_queue_put(&queue, parents->item);
+ commit_list_insert(walk_start[i], &stack);
+ walk_start[i]->object.flags |= STALE;
+
+ while (stack) {
+ struct commit_list *parents;
+ struct commit *c = stack->item;
+
+ repo_parse_commit(r, c);
+
+ if (c->object.flags & RESULT) {
+ c->object.flags &= ~RESULT;
+ if (--count_still_independent <= 1)
+ break;
}
- parents = parents->next;
+
+ if (commit_graph_generation(c) < min_generation) {
+ pop_commit(&stack);
+ continue;
+ }
+
+ parents = c->parents;
+ while (parents) {
+ if (!(parents->item->object.flags & STALE)) {
+ parents->item->object.flags |= STALE;
+ commit_list_insert(parents->item, &stack);
+ break;
+ }
+ parents = parents->next;
+ }
+
+ /* pop if all parents have been visited already */
+ if (!parents)
+ pop_commit(&stack);
}
+ free_commit_list(stack);
}
+ /* clear result */
+ for (i = 0; i < cnt; i++)
+ array[i]->object.flags &= ~RESULT;
+
/* rearrange array */
for (i = count_non_stale = 0; i < cnt; i++) {
if (!(array[i]->object.flags & STALE))