Skip to content

Commit 83e3ad3

Browse files
jonathantanmygitster
authored andcommitted
merge-recursive: symlink's descendants not in way
When the working tree has: - bar (directory) - bar/file (file) - foo (symlink to .) (note that lstat() for "foo/bar" would tell us that it is a directory) and the user merges a commit that deletes the foo symlink and instead contains: - bar (directory, as above) - bar/file (file, as above) - foo (directory) - foo/bar (file) the merge should happen without requiring user intervention. However, this does not happen. This is because dir_in_way(), when checking the working tree, thinks that "foo/bar" is a directory. But a symlink should be treated much the same as a file: since dir_in_way() is only checking to see if there is a directory in the way, we don't want symlinks in leading paths to sometimes cause dir_in_way() to return true. Teach dir_in_way() to also check for symlinks in leading paths before reporting whether a directory is in the way. Helped-by: Elijah Newren <[email protected]> Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5fa0f52 commit 83e3ad3

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

merge-recursive.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ static int dir_in_way(struct index_state *istate, const char *path,
764764

765765
strbuf_release(&dirpath);
766766
return check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode) &&
767-
!(empty_ok && is_empty_dir(path));
767+
!(empty_ok && is_empty_dir(path)) &&
768+
!has_symlink_leading_path(path, strlen(path));
768769
}
769770

770771
/*

t/t3030-merge-recursive.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,34 @@ test_expect_success 'merge-recursive d/f conflict result' '
452452
453453
'
454454

455+
test_expect_success SYMLINKS 'dir in working tree with symlink ancestor does not produce d/f conflict' '
456+
git init sym &&
457+
(
458+
cd sym &&
459+
ln -s . foo &&
460+
mkdir bar &&
461+
>bar/file &&
462+
git add foo bar/file &&
463+
git commit -m "foo symlink" &&
464+
465+
git checkout -b branch1 &&
466+
git commit --allow-empty -m "empty commit" &&
467+
468+
git checkout master &&
469+
git rm foo &&
470+
mkdir foo &&
471+
>foo/bar &&
472+
git add foo/bar &&
473+
git commit -m "replace foo symlink with real foo dir and foo/bar file" &&
474+
475+
git checkout branch1 &&
476+
477+
git cherry-pick master &&
478+
test_path_is_dir foo &&
479+
test_path_is_file foo/bar
480+
)
481+
'
482+
455483
test_expect_success 'reset and 3-way merge' '
456484
457485
git reset --hard "$c2" &&

0 commit comments

Comments
 (0)