merge-ort: copy find_first_merges() implementation from merge-recursive.c

Code is identical for the function body in the two files, the call signature is just slightly different in merge-ort than merge-recursive as noted a couple commits ago. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Jan 1, 2021 at 02:34 UTC 4204cd591b62f3e184f617d01b282b9847298dbd
1 file changed +56 -1
merge-ort.c
+56 -1
@@ -25,6 +25,7 @@
25 #include "dir.h"
26 #include "ll-merge.h"
27 #include "object-store.h"
28 +#include "revision.h"
29 #include "strmap.h"
30 #include "submodule.h"
31 #include "tree.h"
@@ -658,7 +659,61 @@ static int find_first_merges(struct repository *repo,
659 struct commit *b,
660 struct object_array *result)
661 {
661 - die("Not yet implemented.");
662 + int i, j;
663 + struct object_array merges = OBJECT_ARRAY_INIT;
664 + struct commit *commit;
665 + int contains_another;
666 +
667 + char merged_revision[GIT_MAX_HEXSZ + 2];
668 + const char *rev_args[] = { "rev-list", "--merges", "--ancestry-path",
669 + "--all", merged_revision, NULL };
670 + struct rev_info revs;
671 + struct setup_revision_opt rev_opts;
672 +
673 + memset(result, 0, sizeof(struct object_array));
674 + memset(&rev_opts, 0, sizeof(rev_opts));
675 +
676 + /* get all revisions that merge commit a */
677 + xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
678 + oid_to_hex(&a->object.oid));
679 + repo_init_revisions(repo, &revs, NULL);
680 + rev_opts.submodule = path;
681 + /* FIXME: can't handle linked worktrees in submodules yet */
682 + revs.single_worktree = path != NULL;
683 + setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
684 +
685 + /* save all revisions from the above list that contain b */
686 + if (prepare_revision_walk(&revs))
687 + die("revision walk setup failed");
688 + while ((commit = get_revision(&revs)) != NULL) {
689 + struct object *o = &(commit->object);
690 + if (in_merge_bases(b, commit))
691 + add_object_array(o, NULL, &merges);
692 + }
693 + reset_revision_walk();
694 +
695 + /* Now we've got all merges that contain a and b. Prune all
696 + * merges that contain another found merge and save them in
697 + * result.
698 + */
699 + for (i = 0; i < merges.nr; i++) {
700 + struct commit *m1 = (struct commit *) merges.objects[i].item;
701 +
702 + contains_another = 0;
703 + for (j = 0; j < merges.nr; j++) {
704 + struct commit *m2 = (struct commit *) merges.objects[j].item;
705 + if (i != j && in_merge_bases(m2, m1)) {
706 + contains_another = 1;
707 + break;
708 + }
709 + }
710 +
711 + if (!contains_another)
712 + add_object_array(merges.objects[i].item, NULL, result);
713 + }
714 +
715 + object_array_clear(&merges);
716 + return result->nr;
717 }
718
719 static int merge_submodule(struct merge_options *opt,