diff --git a/src/ignore.c b/src/ignore.c index aedc1401e..ac2af4f58 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -263,10 +263,18 @@ int git_ignore__for_path( goto cleanup; /* given a unrooted path in a non-bare repo, resolve it */ - if (workdir && git_path_root(path) < 0) - error = git_path_find_dir(&ignores->dir, path, workdir); - else + if (workdir && git_path_root(path) < 0) { + git_buf local = GIT_BUF_INIT; + + if ((error = git_path_dirname_r(&local, path)) < 0 || + (error = git_path_resolve_relative(&local, 0)) < 0 || + (error = git_path_to_dir(&local)) < 0 || + (error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0) + {;} /* Nothing, we just want to stop on the first error */ + git_buf_free(&local); + } else { error = git_buf_joinpath(&ignores->dir, path, ""); + } if (error < 0) goto cleanup; diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index 27fed2539..91bf984a1 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -252,3 +252,16 @@ void test_attr_ignore__dont_ignore_files_for_folder(void) if (cl_repo_get_bool(g_repo, "core.ignorecase")) assert_is_ignored(false, "dir/TeSt"); } + +void test_attr_ignore__symlink_to_outside(void) +{ +#ifdef GIT_WIN32 + cl_skip(); +#endif + + cl_git_rewritefile("attr/.gitignore", "symlink\n"); + cl_git_mkfile("target", "target"); + cl_git_pass(p_symlink("../target", "attr/symlink")); + assert_is_ignored(true, "symlink"); + assert_is_ignored(true, "lala/../symlink"); +}