On Wed, Sep 18, 2019 at 1:27 PM Jonathan Tan <jonathanta...@google.com> wrote:
>
> 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 <new...@gmail.com>
> Signed-off-by: Jonathan Tan <jonathanta...@google.com>
> ---
> Changes from v1:
>
> - Used has_symlink_leading_path(). This drastically shortens the diff.
> - Updated commit message following suggestions from Junio, Szeder Gábor,
>   and Elijah Newren.
> - Updated test to add prereq and verification that the working tree
>   contains what we want.
> ---
>  merge-recursive.c          |  3 ++-
>  t/t3030-merge-recursive.sh | 28 ++++++++++++++++++++++++++++
>  2 files changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/merge-recursive.c b/merge-recursive.c
> index 6b812d67e3..22a12cfeba 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -764,7 +764,8 @@ static int dir_in_way(struct index_state *istate, const 
> char *path,
>
>         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));
>  }
>
>  /*
> diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
> index ff641b348a..faa8892741 100755
> --- a/t/t3030-merge-recursive.sh
> +++ b/t/t3030-merge-recursive.sh
> @@ -452,6 +452,34 @@ test_expect_success 'merge-recursive d/f conflict 
> result' '
>
>  '
>
> +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" &&
> --

Looks good to me; nice how much it has simplified.  Thanks for working on this.

> 2.23.0.237.gc6a4ce50a0-goog

A total tangent, but what do you use the "-goog" suffix for?

Reply via email to