]> git.ipfire.org Git - thirdparty/git.git/blobdiff - commit-reach.c
Merge branch 'jt/namespaced-ls-refs-fix'
[thirdparty/git.git] / commit-reach.c
index 657a4e9b5a8fe91050f18019942e1afb21ff6193..3ea174788a4f0229460bad65373e974cc3f87c64 100644 (file)
@@ -312,16 +312,17 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 /*
  * Is "commit" an ancestor of one of the "references"?
  */
-int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
+int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
+                            int nr_reference, struct commit **reference)
 {
        struct commit_list *bases;
        int ret = 0, i;
        uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 
-       if (parse_commit(commit))
+       if (repo_parse_commit(r, commit))
                return ret;
        for (i = 0; i < nr_reference; i++) {
-               if (parse_commit(reference[i]))
+               if (repo_parse_commit(r, reference[i]))
                        return ret;
                if (reference[i]->generation < min_generation)
                        min_generation = reference[i]->generation;
@@ -330,7 +331,7 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
        if (commit->generation > min_generation)
                return ret;
 
-       bases = paint_down_to_common(the_repository, commit,
+       bases = paint_down_to_common(r, commit,
                                     nr_reference, reference,
                                     commit->generation);
        if (commit->object.flags & PARENT2)
@@ -344,9 +345,11 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
 /*
  * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
  */
-int in_merge_bases(struct commit *commit, struct commit *reference)
+int repo_in_merge_bases(struct repository *r,
+                       struct commit *commit,
+                       struct commit *reference)
 {
-       return in_merge_bases_many(commit, 1, &reference);
+       return repo_in_merge_bases_many(r, commit, 1, &reference);
 }
 
 struct commit_list *reduce_heads(struct commit_list *heads)
@@ -539,8 +542,8 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
 
 static int compare_commits_by_gen(const void *_a, const void *_b)
 {
-       const struct commit *a = (const struct commit *)_a;
-       const struct commit *b = (const struct commit *)_b;
+       const struct commit *a = *(const struct commit * const *)_a;
+       const struct commit *b = *(const struct commit * const *)_b;
 
        if (a->generation < b->generation)
                return -1;
@@ -603,8 +606,10 @@ int can_all_from_reach_with_flag(struct object_array *from,
                while (stack) {
                        struct commit_list *parent;
 
-                       if (stack->item->object.flags & with_flag) {
+                       if (stack->item->object.flags & (with_flag | RESULT)) {
                                pop_commit(&stack);
+                               if (stack)
+                                       stack->item->object.flags |= RESULT;
                                continue;
                        }
 
@@ -698,3 +703,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;
+}