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 <newren@gmail.com>
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
strbuf_release(&dirpath);
return check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode) &&
- !(empty_ok && is_empty_dir(path));
+ !(empty_ok && is_empty_dir(path)) &&
+ !has_symlink_leading_path(path, strlen(path));
}
/*
'
+test_expect_success SYMLINKS 'dir in working tree with symlink ancestor does not produce d/f conflict' '
+ git init sym &&
+ (
+ cd sym &&
+ ln -s . foo &&
+ mkdir bar &&
+ >bar/file &&
+ git add foo bar/file &&
+ git commit -m "foo symlink" &&
+
+ git checkout -b branch1 &&
+ git commit --allow-empty -m "empty commit" &&
+
+ git checkout master &&
+ git rm foo &&
+ mkdir foo &&
+ >foo/bar &&
+ git add foo/bar &&
+ git commit -m "replace foo symlink with real foo dir and foo/bar file" &&
+
+ git checkout branch1 &&
+
+ git cherry-pick master &&
+ test_path_is_dir foo &&
+ test_path_is_file foo/bar
+ )
+'
+
test_expect_success 'reset and 3-way merge' '
git reset --hard "$c2" &&