Git Mailing List Archive on lore.kernel.org
 help / color / Atom feed
From: "Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Elijah Newren <newren@gmail.com>,
	Derrick Stolee <stolee@gmail.com>,
	Elijah Newren <newren@gmail.com>,
	Elijah Newren <newren@gmail.com>
Subject: [PATCH v2 10/10] merge-ort: add handling for different types of files at same path
Date: Fri, 01 Jan 2021 02:34:48 +0000
Message-ID: <34eb647df40aa61ac961753118112ca2695eab4c.1609468488.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.815.v2.git.1609468488.gitgitgadget@gmail.com>

From: Elijah Newren <newren@gmail.com>

Add some handling that explicitly considers collisions of the following
types:
  * file/submodule
  * file/symlink
  * submodule/symlink
Leaving them as conflicts at the same path are hard for users to
resolve, so move one or both of them aside so that they each get their
own path.

Note that in the case of recursive handling (i.e. call_depth > 0), we
can just use the merge base of the two merge bases as the merge result
much like we do with modify/delete conflicts, binary files, conflicting
submodule values, and so on.

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

diff --git a/merge-ort.c b/merge-ort.c
index 203fa987e43..afe721182e2 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -1521,10 +1521,109 @@ static void process_entry(struct merge_options *opt,
 	} else if (ci->filemask >= 6 &&
 		   (S_IFMT & ci->stages[1].mode) !=
 		   (S_IFMT & ci->stages[2].mode)) {
-		/*
-		 * Two different items from (file/submodule/symlink)
-		 */
-		die("Not yet implemented.");
+		/* Two different items from (file/submodule/symlink) */
+		if (opt->priv->call_depth) {
+			/* Just use the version from the merge base */
+			ci->merged.clean = 0;
+			oidcpy(&ci->merged.result.oid, &ci->stages[0].oid);
+			ci->merged.result.mode = ci->stages[0].mode;
+			ci->merged.is_null = (ci->merged.result.mode == 0);
+		} else {
+			/* Handle by renaming one or both to separate paths. */
+			unsigned o_mode = ci->stages[0].mode;
+			unsigned a_mode = ci->stages[1].mode;
+			unsigned b_mode = ci->stages[2].mode;
+			struct conflict_info *new_ci;
+			const char *a_path = NULL, *b_path = NULL;
+			int rename_a = 0, rename_b = 0;
+
+			new_ci = xmalloc(sizeof(*new_ci));
+
+			if (S_ISREG(a_mode))
+				rename_a = 1;
+			else if (S_ISREG(b_mode))
+				rename_b = 1;
+			else {
+				rename_a = 1;
+				rename_b = 1;
+			}
+
+			path_msg(opt, path, 0,
+				 _("CONFLICT (distinct types): %s had different "
+				   "types on each side; renamed %s of them so "
+				   "each can be recorded somewhere."),
+				 path,
+				 (rename_a && rename_b) ? _("both") : _("one"));
+
+			ci->merged.clean = 0;
+			memcpy(new_ci, ci, sizeof(*new_ci));
+
+			/* Put b into new_ci, removing a from stages */
+			new_ci->merged.result.mode = ci->stages[2].mode;
+			oidcpy(&new_ci->merged.result.oid, &ci->stages[2].oid);
+			new_ci->stages[1].mode = 0;
+			oidcpy(&new_ci->stages[1].oid, &null_oid);
+			new_ci->filemask = 5;
+			if ((S_IFMT & b_mode) != (S_IFMT & o_mode)) {
+				new_ci->stages[0].mode = 0;
+				oidcpy(&new_ci->stages[0].oid, &null_oid);
+				new_ci->filemask = 4;
+			}
+
+			/* Leave only a in ci, fixing stages. */
+			ci->merged.result.mode = ci->stages[1].mode;
+			oidcpy(&ci->merged.result.oid, &ci->stages[1].oid);
+			ci->stages[2].mode = 0;
+			oidcpy(&ci->stages[2].oid, &null_oid);
+			ci->filemask = 3;
+			if ((S_IFMT & a_mode) != (S_IFMT & o_mode)) {
+				ci->stages[0].mode = 0;
+				oidcpy(&ci->stages[0].oid, &null_oid);
+				ci->filemask = 2;
+			}
+
+			/* Insert entries into opt->priv_paths */
+			assert(rename_a || rename_b);
+			if (rename_a) {
+				a_path = unique_path(&opt->priv->paths,
+						     path, opt->branch1);
+				strmap_put(&opt->priv->paths, a_path, ci);
+			}
+
+			if (rename_b)
+				b_path = unique_path(&opt->priv->paths,
+						     path, opt->branch2);
+			else
+				b_path = path;
+			strmap_put(&opt->priv->paths, b_path, new_ci);
+
+			if (rename_a && rename_b) {
+				strmap_remove(&opt->priv->paths, path, 0);
+				/*
+				 * We removed path from opt->priv->paths.  path
+				 * will also eventually need to be freed, but
+				 * it may still be used by e.g.  ci->pathnames.
+				 * So, store it in another string-list for now.
+				 */
+				string_list_append(&opt->priv->paths_to_free,
+						   path);
+			}
+
+			/*
+			 * Do special handling for b_path since process_entry()
+			 * won't be called on it specially.
+			 */
+			strmap_put(&opt->priv->conflicted, b_path, new_ci);
+			record_entry_for_tree(dir_metadata, b_path,
+					      &new_ci->merged);
+
+			/*
+			 * Remaining code for processing this entry should
+			 * think in terms of processing a_path.
+			 */
+			if (a_path)
+				path = a_path;
+		}
 	} else if (ci->filemask >= 6) {
 		/* Need a two-way or three-way content merge */
 		struct version_info merged_file;
-- 
gitgitgadget

  parent reply index

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 ` [PATCH 05/10] merge-ort: flesh out implementation of handle_content_merge() Elijah Newren via GitGitGadget
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   ` Elijah Newren via GitGitGadget [this message]
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=34eb647df40aa61ac961753118112ca2695eab4c.1609468488.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=newren@gmail.com \
    --cc=stolee@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

Git Mailing List Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/git/0 git/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 git git/ https://lore.kernel.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.git


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git