summaryrefslogtreecommitdiff
path: root/merge-ort.c
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2021-01-01 02:34:45 (GMT)
committerJunio C Hamano <gitster@pobox.com>2021-01-04 18:40:45 (GMT)
commitc73cda76b104795d1455ecbf031a18045ab37a84 (patch)
treebc472f3808d3c1cf3edfc4f8ba4987e672a9fce2 /merge-ort.c
parentf591c4724615b2fc1e4dc3d6bfe5da96a88eacbe (diff)
downloadgit-c73cda76b104795d1455ecbf031a18045ab37a84.zip
git-c73cda76b104795d1455ecbf031a18045ab37a84.tar.gz
git-c73cda76b104795d1455ecbf031a18045ab37a84.tar.bz2
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>
Diffstat (limited to 'merge-ort.c')
-rw-r--r--merge-ort.c126
1 files changed, 125 insertions, 1 deletions
diff --git a/merge-ort.c b/merge-ort.c
index a59adb4..2dfab18 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -26,6 +26,7 @@
#include "ll-merge.h"
#include "object-store.h"
#include "strmap.h"
+#include "submodule.h"
#include "tree.h"
#include "unpack-trees.h"
#include "xdiff-interface.h"
@@ -323,6 +324,13 @@ static int err(struct merge_options *opt, const char *err, ...)
return -1;
}
+static void format_commit(struct strbuf *sb,
+ int indent,
+ struct commit *commit)
+{
+ die("Not yet implemented.");
+}
+
__attribute__((format (printf, 4, 5)))
static void path_msg(struct merge_options *opt,
const char *path,
@@ -632,6 +640,15 @@ static int collect_merge_info(struct merge_options *opt,
/*** Function Grouping: functions related to threeway content merges ***/
+static int find_first_merges(struct repository *repo,
+ const char *path,
+ struct commit *a,
+ struct commit *b,
+ struct object_array *result)
+{
+ die("Not yet implemented.");
+}
+
static int merge_submodule(struct merge_options *opt,
const char *path,
const struct object_id *o,
@@ -639,7 +656,114 @@ static int merge_submodule(struct merge_options *opt,
const struct object_id *b,
struct object_id *result)
{
- die("Not yet implemented.");
+ struct commit *commit_o, *commit_a, *commit_b;
+ int parent_count;
+ struct object_array merges;
+ struct strbuf sb = STRBUF_INIT;
+
+ int i;
+ int search = !opt->priv->call_depth;
+
+ /* store fallback answer in result in case we fail */
+ oidcpy(result, opt->priv->call_depth ? o : a);
+
+ /* we can not handle deletion conflicts */
+ if (is_null_oid(o))
+ return 0;
+ if (is_null_oid(a))
+ return 0;
+ if (is_null_oid(b))
+ return 0;
+
+ if (add_submodule_odb(path)) {
+ path_msg(opt, path, 0,
+ _("Failed to merge submodule %s (not checked out)"),
+ path);
+ return 0;
+ }
+
+ if (!(commit_o = lookup_commit_reference(opt->repo, o)) ||
+ !(commit_a = lookup_commit_reference(opt->repo, a)) ||
+ !(commit_b = lookup_commit_reference(opt->repo, b))) {
+ path_msg(opt, path, 0,
+ _("Failed to merge submodule %s (commits not present)"),
+ path);
+ return 0;
+ }
+
+ /* check whether both changes are forward */
+ if (!in_merge_bases(commit_o, commit_a) ||
+ !in_merge_bases(commit_o, commit_b)) {
+ path_msg(opt, path, 0,
+ _("Failed to merge submodule %s "
+ "(commits don't follow merge-base)"),
+ path);
+ return 0;
+ }
+
+ /* Case #1: a is contained in b or vice versa */
+ if (in_merge_bases(commit_a, commit_b)) {
+ oidcpy(result, b);
+ path_msg(opt, path, 1,
+ _("Note: Fast-forwarding submodule %s to %s"),
+ path, oid_to_hex(b));
+ return 1;
+ }
+ if (in_merge_bases(commit_b, commit_a)) {
+ oidcpy(result, a);
+ path_msg(opt, path, 1,
+ _("Note: Fast-forwarding submodule %s to %s"),
+ path, oid_to_hex(a));
+ return 1;
+ }
+
+ /*
+ * Case #2: There are one or more merges that contain a and b in
+ * the submodule. If there is only one, then present it as a
+ * suggestion to the user, but leave it marked unmerged so the
+ * user needs to confirm the resolution.
+ */
+
+ /* Skip the search if makes no sense to the calling context. */
+ if (!search)
+ return 0;
+
+ /* find commit which merges them */
+ parent_count = find_first_merges(opt->repo, path, commit_a, commit_b,
+ &merges);
+ switch (parent_count) {
+ case 0:
+ path_msg(opt, path, 0, _("Failed to merge submodule %s"), path);
+ break;
+
+ case 1:
+ format_commit(&sb, 4,
+ (struct commit *)merges.objects[0].item);
+ path_msg(opt, path, 0,
+ _("Failed to merge submodule %s, but a possible merge "
+ "resolution exists:\n%s\n"),
+ path, sb.buf);
+ path_msg(opt, path, 1,
+ _("If this is correct simply add it to the index "
+ "for example\n"
+ "by using:\n\n"
+ " git update-index --cacheinfo 160000 %s \"%s\"\n\n"
+ "which will accept this suggestion.\n"),
+ oid_to_hex(&merges.objects[0].item->oid), path);
+ strbuf_release(&sb);
+ break;
+ default:
+ for (i = 0; i < merges.nr; i++)
+ format_commit(&sb, 4,
+ (struct commit *)merges.objects[i].item);
+ path_msg(opt, path, 0,
+ _("Failed to merge submodule %s, but multiple "
+ "possible merges exist:\n%s"), path, sb.buf);
+ strbuf_release(&sb);
+ }
+
+ object_array_clear(&merges);
+ return 0;
}
static int merge_3way(struct merge_options *opt,