merge-ort: copy and adapt merge_submodule() from merge-recursive.c

Take merge_submodule() from merge-recursive.c and make slight adjustments, predominantly around deferring output using path_msg() instead of using merge-recursive's output() and show() functions. There's also a fix for recursive cases (when call_depth > 0) and a slight change to argument order for find_first_merges(). find_first_merges() and format_commit() are left unimplemented for now, but will be added by subsequent commits. 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 c73cda76b104795d1455ecbf031a18045ab37a84
1 file changed +125 -1
merge-ort.c
+125 -1
@@ -26,6 +26,7 @@
26 #include "ll-merge.h"
27 #include "object-store.h"
28 #include "strmap.h"
29 +#include "submodule.h"
30 #include "tree.h"
31 #include "unpack-trees.h"
32 #include "xdiff-interface.h"
@@ -323,6 +324,13 @@ static int err(struct merge_options *opt, const char *err, ...)
324 return -1;
325 }
326
327 +static void format_commit(struct strbuf *sb,
328 + int indent,
329 + struct commit *commit)
330 +{
331 + die("Not yet implemented.");
332 +}
333 +
334 __attribute__((format (printf, 4, 5)))
335 static void path_msg(struct merge_options *opt,
336 const char *path,
@@ -632,6 +640,15 @@ static int collect_merge_info(struct merge_options *opt,
640
641 /*** Function Grouping: functions related to threeway content merges ***/
642
643 +static int find_first_merges(struct repository *repo,
644 + const char *path,
645 + struct commit *a,
646 + struct commit *b,
647 + struct object_array *result)
648 +{
649 + die("Not yet implemented.");
650 +}
651 +
652 static int merge_submodule(struct merge_options *opt,
653 const char *path,
654 const struct object_id *o,
@@ -639,7 +656,114 @@ static int merge_submodule(struct merge_options *opt,
656 const struct object_id *b,
657 struct object_id *result)
658 {
642 - die("Not yet implemented.");
659 + struct commit *commit_o, *commit_a, *commit_b;
660 + int parent_count;
661 + struct object_array merges;
662 + struct strbuf sb = STRBUF_INIT;
663 +
664 + int i;
665 + int search = !opt->priv->call_depth;
666 +
667 + /* store fallback answer in result in case we fail */
668 + oidcpy(result, opt->priv->call_depth ? o : a);
669 +
670 + /* we can not handle deletion conflicts */
671 + if (is_null_oid(o))
672 + return 0;
673 + if (is_null_oid(a))
674 + return 0;
675 + if (is_null_oid(b))
676 + return 0;
677 +
678 + if (add_submodule_odb(path)) {
679 + path_msg(opt, path, 0,
680 + _("Failed to merge submodule %s (not checked out)"),
681 + path);
682 + return 0;
683 + }
684 +
685 + if (!(commit_o = lookup_commit_reference(opt->repo, o)) ||
686 + !(commit_a = lookup_commit_reference(opt->repo, a)) ||
687 + !(commit_b = lookup_commit_reference(opt->repo, b))) {
688 + path_msg(opt, path, 0,
689 + _("Failed to merge submodule %s (commits not present)"),
690 + path);
691 + return 0;
692 + }
693 +
694 + /* check whether both changes are forward */
695 + if (!in_merge_bases(commit_o, commit_a) ||
696 + !in_merge_bases(commit_o, commit_b)) {
697 + path_msg(opt, path, 0,
698 + _("Failed to merge submodule %s "
699 + "(commits don't follow merge-base)"),
700 + path);
701 + return 0;
702 + }
703 +
704 + /* Case #1: a is contained in b or vice versa */
705 + if (in_merge_bases(commit_a, commit_b)) {
706 + oidcpy(result, b);
707 + path_msg(opt, path, 1,
708 + _("Note: Fast-forwarding submodule %s to %s"),
709 + path, oid_to_hex(b));
710 + return 1;
711 + }
712 + if (in_merge_bases(commit_b, commit_a)) {
713 + oidcpy(result, a);
714 + path_msg(opt, path, 1,
715 + _("Note: Fast-forwarding submodule %s to %s"),
716 + path, oid_to_hex(a));
717 + return 1;
718 + }
719 +
720 + /*
721 + * Case #2: There are one or more merges that contain a and b in
722 + * the submodule. If there is only one, then present it as a
723 + * suggestion to the user, but leave it marked unmerged so the
724 + * user needs to confirm the resolution.
725 + */
726 +
727 + /* Skip the search if makes no sense to the calling context. */
728 + if (!search)
729 + return 0;
730 +
731 + /* find commit which merges them */
732 + parent_count = find_first_merges(opt->repo, path, commit_a, commit_b,
733 + &merges);
734 + switch (parent_count) {
735 + case 0:
736 + path_msg(opt, path, 0, _("Failed to merge submodule %s"), path);
737 + break;
738 +
739 + case 1:
740 + format_commit(&sb, 4,
741 + (struct commit *)merges.objects[0].item);
742 + path_msg(opt, path, 0,
743 + _("Failed to merge submodule %s, but a possible merge "
744 + "resolution exists:\n%s\n"),
745 + path, sb.buf);
746 + path_msg(opt, path, 1,
747 + _("If this is correct simply add it to the index "
748 + "for example\n"
749 + "by using:\n\n"
750 + " git update-index --cacheinfo 160000 %s \"%s\"\n\n"
751 + "which will accept this suggestion.\n"),
752 + oid_to_hex(&merges.objects[0].item->oid), path);
753 + strbuf_release(&sb);
754 + break;
755 + default:
756 + for (i = 0; i < merges.nr; i++)
757 + format_commit(&sb, 4,
758 + (struct commit *)merges.objects[i].item);
759 + path_msg(opt, path, 0,
760 + _("Failed to merge submodule %s, but multiple "
761 + "possible merges exist:\n%s"), path, sb.buf);
762 + strbuf_release(&sb);
763 + }
764 +
765 + object_array_clear(&merges);
766 + return 0;
767 }
768
769 static int merge_3way(struct merge_options *opt,