All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Elijah Newren <newren@gmail.com>, Elijah Newren <newren@gmail.com>
Subject: [PATCH 05/10] merge-ort: flesh out implementation of handle_content_merge()
Date: Fri, 18 Dec 2020 05:51:22 +0000	[thread overview]
Message-ID: <0e7321e67f83c197e84ad7b281ab2ce79c90b784.1608270687.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.815.git.1608270687.gitgitgadget@gmail.com>

From: Elijah Newren <newren@gmail.com>

This implementation is based heavily on merge_mode_and_contents() from
merge-recursive.c, though it has some fixes for recursive merges (i.e.
when call_depth > 0), and has a number of changes throughout based on
slight differences in data structures and in how the functions are
called.

It is, however, based on two new helper functions -- merge_3way() and
merge_submodule -- for which we only provide die-not-implemented stubs
at this point.  Future commits will add implementations of these
functions.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 merge-ort.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 143 insertions(+), 6 deletions(-)

diff --git a/merge-ort.c b/merge-ort.c
index 47e230fe341..2cfb7ffa3b0 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -631,6 +631,28 @@ static int collect_merge_info(struct merge_options *opt,
 
 /*** Function Grouping: functions related to threeway content merges ***/
 
+static int merge_submodule(struct merge_options *opt,
+			   const char *path,
+			   const struct object_id *o,
+			   const struct object_id *a,
+			   const struct object_id *b,
+			   struct object_id *result)
+{
+	die("Not yet implemented.");
+}
+
+static int merge_3way(struct merge_options *opt,
+		      const char *path,
+		      const struct object_id *o,
+		      const struct object_id *a,
+		      const struct object_id *b,
+		      const char *pathnames[3],
+		      const int extra_marker_size,
+		      mmbuffer_t *result_buf)
+{
+	die("Not yet implemented.");
+}
+
 static int handle_content_merge(struct merge_options *opt,
 				const char *path,
 				const struct version_info *o,
@@ -640,14 +662,129 @@ static int handle_content_merge(struct merge_options *opt,
 				const int extra_marker_size,
 				struct version_info *result)
 {
-	int clean = 0;
 	/*
-	 * TODO: Needs a two-way or three-way content merge, but we're
-	 * just being lazy and copying the version from HEAD and
-	 * leaving it as conflicted.
+	 * path is the target location where we want to put the file, and
+	 * is used to determine any normalization rules in ll_merge.
+	 *
+	 * The normal case is that path and all entries in pathnames are
+	 * identical, though renames can affect which path we got one of
+	 * the three blobs to merge on various sides of history.
+	 *
+	 * extra_marker_size is the amount to extend conflict markers in
+	 * ll_merge; this is neeed if we have content merges of content
+	 * merges, which happens for example with rename/rename(2to1) and
+	 * rename/add conflicts.
 	 */
-	result->mode = a->mode;
-	oidcpy(&result->oid, &a->oid);
+	unsigned clean = 1;
+
+	/*
+	 * handle_content_merge() needs both files to be of the same type, i.e.
+	 * both files OR both submodules OR both symlinks.  Conflicting types
+	 * needs to be handled elsewhere.
+	 */
+	assert((S_IFMT & a->mode) == (S_IFMT & b->mode));
+
+	/* Merge modes */
+	if (a->mode == b->mode || a->mode == o->mode)
+		result->mode = b->mode;
+	else {
+		/* must be the 100644/100755 case */
+		assert(S_ISREG(a->mode));
+		result->mode = a->mode;
+		clean = (b->mode == o->mode);
+		/*
+		 * FIXME: If opt->priv->call_depth && !clean, then we really
+		 * should not make result->mode match either a->mode or
+		 * b->mode; that causes t6036 "check conflicting mode for
+		 * regular file" to fail.  It would be best to use some other
+		 * mode, but we'll confuse all kinds of stuff if we use one
+		 * where S_ISREG(result->mode) isn't true, and if we use
+		 * something like 0100666, then tree-walk.c's calls to
+		 * canon_mode() will just normalize that to 100644 for us and
+		 * thus not solve anything.
+		 *
+		 * Figure out if there's some kind of way we can work around
+		 * this...
+		 */
+	}
+
+	/*
+	 * Trivial oid merge.
+	 *
+	 * Note: While one might assume that the next four lines would
+	 * be unnecessary due to the fact that match_mask is often
+	 * setup and already handled, renames don't always take care
+	 * of that.
+	 */
+	if (oideq(&a->oid, &b->oid) || oideq(&a->oid, &o->oid))
+		oidcpy(&result->oid, &b->oid);
+	else if (oideq(&b->oid, &o->oid))
+		oidcpy(&result->oid, &a->oid);
+
+	/* Remaining rules depend on file vs. submodule vs. symlink. */
+	else if (S_ISREG(a->mode)) {
+		mmbuffer_t result_buf;
+		int ret = 0, merge_status;
+		int two_way;
+
+		/*
+		 * If 'o' is different type, treat it as null so we do a
+		 * two-way merge.
+		 */
+		two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));
+
+		merge_status = merge_3way(opt, path,
+					  two_way ? &null_oid : &o->oid,
+					  &a->oid, &b->oid,
+					  pathnames, extra_marker_size,
+					  &result_buf);
+
+		if ((merge_status < 0) || !result_buf.ptr)
+			ret = err(opt, _("Failed to execute internal merge"));
+
+		if (!ret &&
+		    write_object_file(result_buf.ptr, result_buf.size,
+				      blob_type, &result->oid))
+			ret = err(opt, _("Unable to add %s to database"),
+				  path);
+
+		free(result_buf.ptr);
+		if (ret)
+			return -1;
+		clean &= (merge_status == 0);
+		path_msg(opt, path, 1, _("Auto-merging %s"), path);
+	} else if (S_ISGITLINK(a->mode)) {
+		int two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));
+		clean = merge_submodule(opt, pathnames[0],
+					two_way ? &null_oid : &o->oid,
+					&a->oid, &b->oid, &result->oid);
+		if (opt->priv->call_depth && two_way && !clean) {
+			result->mode = o->mode;
+			oidcpy(&result->oid, &o->oid);
+		}
+	} else if (S_ISLNK(a->mode)) {
+		if (opt->priv->call_depth) {
+			clean = 0;
+			result->mode = o->mode;
+			oidcpy(&result->oid, &o->oid);
+		} else {
+			switch (opt->recursive_variant) {
+			case MERGE_VARIANT_NORMAL:
+				clean = 0;
+				oidcpy(&result->oid, &a->oid);
+				break;
+			case MERGE_VARIANT_OURS:
+				oidcpy(&result->oid, &a->oid);
+				break;
+			case MERGE_VARIANT_THEIRS:
+				oidcpy(&result->oid, &b->oid);
+				break;
+			}
+		}
+	} else
+		BUG("unsupported object type in the tree: %06o for %s",
+		    a->mode, path);
+
 	return clean;
 }
 
-- 
gitgitgadget


  parent reply	other threads:[~2020-12-18  5:52 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-18  5:51 [PATCH 00/10] merge-ort: add more handling of basic conflict types Elijah Newren via GitGitGadget
2020-12-18  5:51 ` [PATCH 01/10] merge-ort: handle D/F conflict where directory disappears due to merge Elijah Newren via GitGitGadget
2020-12-30 14:06   ` Derrick Stolee
2020-12-30 15:13     ` Elijah Newren
2020-12-31 11:17       ` Derrick Stolee
2020-12-31 17:13         ` Elijah Newren
2020-12-18  5:51 ` [PATCH 02/10] merge-ort: handle directory/file conflicts that remain Elijah Newren via GitGitGadget
2020-12-18  5:51 ` [PATCH 03/10] merge-ort: implement unique_path() helper Elijah Newren via GitGitGadget
2020-12-30 14:16   ` Derrick Stolee
2020-12-30 15:10     ` Elijah Newren
2020-12-31 11:19       ` Derrick Stolee
2020-12-18  5:51 ` [PATCH 04/10] merge-ort: handle book-keeping around two- and three-way content merge Elijah Newren via GitGitGadget
2020-12-18  5:51 ` Elijah Newren via GitGitGadget [this message]
2020-12-18  5:51 ` [PATCH 06/10] merge-ort: copy and adapt merge_3way() from merge-recursive.c Elijah Newren via GitGitGadget
2020-12-18  5:51 ` [PATCH 07/10] merge-ort: copy and adapt merge_submodule() " Elijah Newren via GitGitGadget
2020-12-18  5:51 ` [PATCH 08/10] merge-ort: implement format_commit() Elijah Newren via GitGitGadget
2020-12-18  5:51 ` [PATCH 09/10] merge-ort: copy find_first_merges() implementation from merge-recursive.c Elijah Newren via GitGitGadget
2020-12-18  5:51 ` [PATCH 10/10] merge-ort: add handling for different types of files at same path Elijah Newren via GitGitGadget
2020-12-29  0:44 ` [PATCH 00/10] merge-ort: add more handling of basic conflict types Elijah Newren
2021-01-01  2:34 ` [PATCH v2 " Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 01/10] merge-ort: handle D/F conflict where directory disappears due to merge Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 02/10] merge-ort: handle directory/file conflicts that remain Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 03/10] merge-ort: implement unique_path() helper Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 04/10] merge-ort: handle book-keeping around two- and three-way content merge Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 05/10] merge-ort: flesh out implementation of handle_content_merge() Elijah Newren via GitGitGadget
2021-03-04 16:28     ` A merge-ort TODO comment, and how to test merge-ort? Ævar Arnfjörð Bjarmason
2021-03-04 19:43       ` Elijah Newren
2021-03-04 21:29         ` Ævar Arnfjörð Bjarmason
2021-03-04 22:45           ` Elijah Newren
2021-03-08 14:49             ` Ævar Arnfjörð Bjarmason
2021-01-01  2:34   ` [PATCH v2 06/10] merge-ort: copy and adapt merge_3way() from merge-recursive.c Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 07/10] merge-ort: copy and adapt merge_submodule() " Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 08/10] merge-ort: implement format_commit() Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 09/10] merge-ort: copy find_first_merges() implementation from merge-recursive.c Elijah Newren via GitGitGadget
2021-01-01  2:34   ` [PATCH v2 10/10] merge-ort: add handling for different types of files at same path Elijah Newren via GitGitGadget
2021-01-05 14:23   ` [PATCH v2 00/10] merge-ort: add more handling of basic conflict types Derrick Stolee
2021-01-06 19:20     ` Elijah Newren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0e7321e67f83c197e84ad7b281ab2ce79c90b784.1608270687.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=newren@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.