Subject: [PATCH] fix recursive-merge of empty files with different permissions

From: Clemens Buchacher <[email-masked]>
Date: Sat, 8 Mar 2008 18:17:26 +0100

If git-merge-recursive attempts to merge two empty new files with
different executable flags, eventually xdl_merge() is called and produces
empty diffs for both files and therefore does not choose either file as
successor. Make xdl_merge() choose one of the files instead.

Signed-off-by: Clemens Buchacher <[email-masked]>
---

Hi,

The change in indentation makes this patch look larger than it is. All I
actually did was remove the "if (xscr1 || xscr2)" condition.

Previously to this patch the included test showed the following output:

	Merging a with b
	Merging:
	82712b3 branch a
	7eacd6f branch b
	found 1 common ancestor(s):
	33b7ba5 initial commit
	Auto-merged a
	fatal: Failed to execute internal merge

I do not understand why, but this does not happen if the file permissions are
the same.

Thanks,
Clemens

 t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
 xdiff/xmerge.c             |   30 ++++++++++++++----------------
 2 files changed, 37 insertions(+), 16 deletions(-)
 create mode 100755 t/t6031-merge-recursive.sh

diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
new file mode 100755
index 0000000..4e3456b
--- /dev/null
+++ b/t/t6031-merge-recursive.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description='merge-recursive corner cases'
+. ./test-lib.sh
+
+test_expect_success 'merge empty files with different permission flags' '
+	: >dummy &&
+	git add dummy &&
+	git commit -m "initial commit" &&
+	git checkout -b a master &&
+	: >a &&
+	git add a &&
+	git commit -m "branch a" &&
+	git checkout -b b master &&
+	: >a &&
+	chmod +x a &&
+	git add a &&
+	git commit -m "branch b" &&
+	git checkout master &&
+	git merge-recursive master -- a b
+'
+
+test_done
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 82b3573..92127e1 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -470,23 +470,21 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
 		return -1;
 	}
 	status = 0;
-	if (xscr1 || xscr2) {
-		if (!xscr1) {
-			result->ptr = xdl_malloc(mf2->size);
-			memcpy(result->ptr, mf2->ptr, mf2->size);
-			result->size = mf2->size;
-		} else if (!xscr2) {
-			result->ptr = xdl_malloc(mf1->size);
-			memcpy(result->ptr, mf1->ptr, mf1->size);
-			result->size = mf1->size;
-		} else {
-			status = xdl_do_merge(&xe1, xscr1, name1,
-					      &xe2, xscr2, name2,
-					      level, xpp, result);
-		}
-		xdl_free_script(xscr1);
-		xdl_free_script(xscr2);
+	if (!xscr1) {
+		result->ptr = xdl_malloc(mf2->size);
+		memcpy(result->ptr, mf2->ptr, mf2->size);
+		result->size = mf2->size;
+	} else if (!xscr2) {
+		result->ptr = xdl_malloc(mf1->size);
+		memcpy(result->ptr, mf1->ptr, mf1->size);
+		result->size = mf1->size;
+	} else {
+		status = xdl_do_merge(&xe1, xscr1, name1,
+				      &xe2, xscr2, name2,
+				      level, xpp, result);
 	}
+	xdl_free_script(xscr1);
+	xdl_free_script(xscr2);
 	xdl_free_env(&xe1);
 	xdl_free_env(&xe2);
 
-- 
1.5.4.3.468.g36990.dirty