Commit 21baf7ab by Patrick Steinhardt

ignore: treat paths with trailing "/" as directories

The function `git_ignore_path_is_ignored` is there to test the
ignore status of paths that need not necessarily exist inside of
a repository. This has the implication that for a given path, we
cannot always decide whether it references a directory or a file,
and we need to distinguish those cases because ignore rules may
treat those differently. E.g. given the following gitignore file:

    *
    !/**/

we'd only want to unignore directories, while keeping files
ignored. But still, calling `git_ignore_path_is_ignored("dir/")`
will say that this directory is ignored because it treats "dir/"
as a file path.

As said, the `is_ignored` function cannot always decide whether
the given path is a file or directory, and thus it may produce
wrong results in some cases. While this is unfixable in the
general case, we can do better when we are being passed a path
name with a trailing path separator (e.g. "dir/") and always
treat them as directories.
parent 71424f63
...@@ -534,7 +534,9 @@ int git_ignore_path_is_ignored( ...@@ -534,7 +534,9 @@ int git_ignore_path_is_ignored(
memset(&path, 0, sizeof(path)); memset(&path, 0, sizeof(path));
memset(&ignores, 0, sizeof(ignores)); memset(&ignores, 0, sizeof(ignores));
if (git_repository_is_bare(repo)) if (!git__suffixcmp(pathname, "/"))
dir_flag = GIT_DIR_FLAG_TRUE;
else if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE; dir_flag = GIT_DIR_FLAG_FALSE;
if ((error = git_attr_path__init(&path, pathname, workdir, dir_flag)) < 0 || if ((error = git_attr_path__init(&path, pathname, workdir, dir_flag)) < 0 ||
......
...@@ -397,3 +397,19 @@ void test_attr_ignore__ignored_subdirfiles_with_negations(void) ...@@ -397,3 +397,19 @@ void test_attr_ignore__ignored_subdirfiles_with_negations(void)
assert_is_ignored(true, "dir/sub1/c.test"); assert_is_ignored(true, "dir/sub1/c.test");
} }
void test_attr_ignore__negative_directory_rules_only_match_directories(void)
{
cl_git_rewritefile(
"attr/.gitignore",
"*\n"
"!/**/\n"
"!*.keep\n"
"!.gitignore\n"
);
assert_is_ignored(true, "src");
assert_is_ignored(true, "src/A");
assert_is_ignored(false, "src/");
assert_is_ignored(false, "src/A.keep");
assert_is_ignored(false, ".gitignore");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment