git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] merge-tree: sometimes, d/f conflict is not an issue

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Jul 8, 2007, 04:35 UTC
Message-ID
<Pine.LNX.4.64.0707080526170.4093@racer.site>
In-Reply-To
<Pine.LNX.4.64.0707080311280.4093@racer.site>
Hi,
On Sun, 8 Jul 2007, Johannes Schindelin wrote:
> Well, I try to cobble up a patch for merge-recursive like you suggested, 
> and stay away from threeway_merge() as far as I can, for the rest of my 
> life.

Here is a WIP. Note: it only does half of the job. For performance reasons, we do not write out the working tree changes for intermediate merges. However, in the last step, we do. And this patch does not reflect that, but only updates the index.

Ciao, Dscho

 merge-recursive.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index dbd06aa..99da2bb 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -243,6 +243,92 @@ static int git_merge_trees(int index_only,
 	return rc;
 }
 
+/*
+ * If there were dir/file conflicts, which are not really dir/file
+ * conflicts, because only one side changed anything, take that
+ * side instead of outputting silly conflicts.
+ *
+ * NOTE! unpack_trees() would have a much better chance at resolving
+ * these conflicts, since it gets the _tree_ objects we have to
+ * reconstruct tediously, and it could get away with one simple
+ * comparison between sha1's, while that is not possible here.
+ */
+static inline int is_df(struct cache_entry *in_dir, struct cache_entry *file)
+{
+	int len = ce_namelen(file);
+	const char *name = in_dir->name;
+	return !memcmp(name, file->name, len) && name[len] == '/';
+}
+
+static int try_to_fix_up_df_conflicts_which_are_none(const unsigned char *base,
+		const unsigned char *head, const unsigned char *merge)
+{
+	int i;
+	for (i = 0; i + 2 < active_nr; i++) {
+		int last;
+		unsigned char sha1[20], sha2[20];
+		unsigned dummy;
+		char *name;
+		struct cache_entry *ce = active_cache[i], *ce1, *ce2;
+
+		if (ce_stage(ce) == 0)
+			continue;
+		ce1 = active_cache[i + 1];
+		ce2 = active_cache[i + 2];
+		if (ce_same_name(ce, ce2) || !is_df(ce2, ce)) {
+			/* not a d/f conflict */
+			i += 2;
+			continue;
+		}
+		for (last = i + 3; last < active_nr &&
+				is_df(active_cache[last], ce); last++)
+			; /* do nothing */
+		/* check if HEAD as an unchanged file, remote a dir */
+		if (ce_same_name(ce, ce1)) {
+			if (ce_stage(ce) != 1 ||
+					hashcmp(ce->sha1, ce1->sha1)) {
+				/* file was changed */
+				i = last - 1;
+				continue;
+			}
+			/* other side removed file, added dir */
+			if (!remove_file_from_cache(ce->name))
+				return error("index error");
+			for (i -= 2, last -= 2; i < last; i++)
+				active_cache[i]->ce_flags &=
+					~ntohs(CE_STAGEMASK);
+			i--;
+			continue;
+		}
+		if (i + 1 == last)
+			continue;
+		/* check if HEAD changed dir to a file */
+		if (ce_stage(ce) == 1) {
+			i = last - 1;
+			continue;
+		}
+		name = xstrndup(ce->name, ce_namelen(ce));
+		if (get_tree_entry(base, name, sha1, &dummy) ||
+				get_tree_entry(ce_stage(ce) == 2 ?
+					merge : head,
+					name, sha2, &dummy)) {
+			free(name);
+			i = last - 1;
+			continue;
+		}
+		free(name);
+		if (!hashcmp(sha1, sha2)) {
+			/* remove tree */
+			memmove(active_cache + i + 1, active_cache + last,
+				(active_nr - last) *
+				sizeof(struct cache_entry *));
+			active_nr -= last - i - 1;
+			ce->ce_flags &= ~ntohs(CE_STAGEMASK);
+		}
+	}
+	return 0;
+}
+
 static int unmerged_index(void)
 {
 	int i;
@@ -1520,6 +1606,8 @@ static int merge_trees(struct tree *head,
 		    sha1_to_hex(head->object.sha1),
 		    sha1_to_hex(merge->object.sha1));
 
+	try_to_fix_up_df_conflicts_which_are_none(common->object.sha1,
+			head->object.sha1, merge->object.sha1);
 	if (unmerged_index()) {
 		struct path_list *entries, *re_head, *re_merge;
 		int i;
Previous: Johannes SchindelinNext: Junio C Hamano
Message 14 of 23 in “unexpected git-cherry-pick conflict”
  1. Gerrit PapeJun 13, 2007
  2. Johannes SchindelinJun 13, 2007
  3. Gerrit PapeJun 13, 2007
  4. Johannes SchindelinJun 13, 2007
  5. Gerrit PapeJun 25, 2007
  6. Johannes SchindelinJun 25, 2007
  7. Johannes SchindelinJul 7, 2007
  8. Gerrit PapeDec 21, 2007
  9. Junio C HamanoDec 22, 2007
  10. merge-tree: sometimes, d/f conflict is not an issueJohannes Schindelin, Jul 8, 2007
  11. Junio C HamanoJul 8, 2007
  12. Johannes SchindelinJul 8, 2007
  13. Johannes SchindelinJul 8, 2007
  14. Johannes SchindelinJul 8, 2007
  15. Junio C HamanoJul 8, 2007
  16. Junio C HamanoJul 8, 2007
  17. Johannes SchindelinJul 8, 2007
  18. Junio C HamanoJul 8, 2007
  19. merge-one-file, was Re: [PATCH] merge-tree: sometimes, d/f conflict is not an issueJohannes Schindelin, Jul 9, 2007
  20. 1/2 merge-recursive: sometimes, d/f conflict is not an issueJohannes Schindelin, Jul 17, 2007
  21. Gerrit PapeAug 8, 2007
  22. 2/2 Add tests for cherry-pick d/f conflict which should be noneJohannes Schindelin, Jul 17, 2007
  23. Johannes SchindelinJul 8, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.