diff options
author | Junio C Hamano <gitster@pobox.com> | 2018-11-13 22:37:24 +0900 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2018-11-13 22:37:24 +0900 |
commit | 291123e69babcbbab720705a1bc1e6f0ba3012a4 (patch) | |
tree | de927178be4e839f7e23b8f05ed56067370744a1 /commit-reach.c | |
parent | 1961efecae1ef937aa1d571add4eae03a8c8303b (diff) | |
parent | 85daa01f6b80cb6eb14c5f484a6da9f0b1247143 (diff) |
Merge branch 'ds/add-missing-tags'
The history traversal used to implement the tag-following has been
optimized by introducing a new helper.
* ds/add-missing-tags:
remote: make add_missing_tags() linear
test-reach: test get_reachable_subset
commit-reach: implement get_reachable_subset
Diffstat (limited to 'commit-reach.c')
-rw-r--r-- | commit-reach.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/commit-reach.c b/commit-reach.c index a9da65c462..d5a39defd3 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -690,3 +690,72 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, object_array_clear(&from_objs); return result; } + +struct commit_list *get_reachable_subset(struct commit **from, int nr_from, + struct commit **to, int nr_to, + unsigned int reachable_flag) +{ + struct commit **item; + struct commit *current; + struct commit_list *found_commits = NULL; + struct commit **to_last = to + nr_to; + struct commit **from_last = from + nr_from; + uint32_t min_generation = GENERATION_NUMBER_INFINITY; + int num_to_find = 0; + + struct prio_queue queue = { compare_commits_by_gen_then_commit_date }; + + for (item = to; item < to_last; item++) { + struct commit *c = *item; + + parse_commit(c); + if (c->generation < min_generation) + min_generation = c->generation; + + if (!(c->object.flags & PARENT1)) { + c->object.flags |= PARENT1; + num_to_find++; + } + } + + for (item = from; item < from_last; item++) { + struct commit *c = *item; + if (!(c->object.flags & PARENT2)) { + c->object.flags |= PARENT2; + parse_commit(c); + + prio_queue_put(&queue, *item); + } + } + + while (num_to_find && (current = prio_queue_get(&queue)) != NULL) { + struct commit_list *parents; + + if (current->object.flags & PARENT1) { + current->object.flags &= ~PARENT1; + current->object.flags |= reachable_flag; + commit_list_insert(current, &found_commits); + num_to_find--; + } + + for (parents = current->parents; parents; parents = parents->next) { + struct commit *p = parents->item; + + parse_commit(p); + + if (p->generation < min_generation) + continue; + + if (p->object.flags & PARENT2) + continue; + + p->object.flags |= PARENT2; + prio_queue_put(&queue, p); + } + } + + clear_commit_marks_many(nr_to, to, PARENT1); + clear_commit_marks_many(nr_from, from, PARENT2); + + return found_commits; +} |