diff --git a/merge-recursive.c b/merge-recursive.c index 34e3167caf..d97cbf7d16 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1028,9 +1028,20 @@ static struct merge_file_info merge_file(struct diff_filespec *o, if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1)) result.merge = 1; - result.mode = a->mode == o->mode ? b->mode: a->mode; + /* + * Merge modes + */ + if (a->mode == b->mode || a->mode == o->mode) + result.mode = b->mode; + else { + result.mode = a->mode; + if (b->mode != o->mode) { + result.clean = 0; + result.merge = 1; + } + } - if (sha_eq(a->sha1, o->sha1)) + if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, o->sha1)) hashcpy(result.sha, b->sha1); else if (sha_eq(b->sha1, o->sha1)) hashcpy(result.sha, a->sha1); diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh new file mode 100755 index 0000000000..5bb6b93780 --- /dev/null +++ b/t/t6031-merge-recursive.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='merge-recursive: handle file mode' +. ./test-lib.sh + +test_expect_success 'mode change in one branch: keep changed version' ' + : >file1 && + git add file1 && + git commit -m initial && + git checkout -b a1 master && + : >dummy && + git add dummy && + git commit -m a && + git checkout -b b1 master && + chmod +x file1 && + git add file1 && + git commit -m b1 && + git checkout a1 && + git merge-recursive master -- a1 b1 && + test -x file1 +' + +test_expect_success 'mode change in both branches: expect conflict' ' + git reset --hard HEAD && + git checkout -b a2 master && + : >file2 && + H=$(git hash-object file2) && + chmod +x file2 && + git add file2 && + git commit -m a2 && + git checkout -b b2 master && + : >file2 && + git add file2 && + git commit -m b2 && + git checkout a2 && + ( + git merge-recursive master -- a2 b2 + test $? = 1 + ) && + git ls-files -u >actual && + ( + echo "100755 $H 2 file2" + echo "100644 $H 3 file2" + ) >expect && + diff -u actual expect && + test -x file2 +' + +test_done