diff --git a/src/attr_file.c b/src/attr_file.c index 0bb761d04..e30ea5e0c 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -395,9 +395,13 @@ bool git_attr_fnmatch__match( if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) { bool samename; - /* for attribute checks or root ignore checks, fail match */ + /* + * for attribute checks or checks at the root of this match's + * containing_dir (or root of the repository if no containing_dir), + * do not match. + */ if (!(match->flags & GIT_ATTR_FNMATCH_IGNORE) || - path->basename == path->path) + path->basename == relpath) return false; flags |= FNM_LEADING_DIR; diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index 3a193890a..a089ee408 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -291,3 +291,15 @@ void test_attr_ignore__symlink_to_outside(void) assert_is_ignored(true, "symlink"); assert_is_ignored(true, "lala/../symlink"); } + +void test_attr_ignore__test(void) +{ + cl_git_rewritefile("attr/.gitignore", + "/*/\n" + "!/src\n"); + assert_is_ignored(false, "src/foo.c"); + assert_is_ignored(false, "src/foo/foo.c"); + assert_is_ignored(false, "README.md"); + assert_is_ignored(true, "dist/foo.o"); + assert_is_ignored(true, "bin/foo"); +} diff --git a/tests/status/ignore.c b/tests/status/ignore.c index 251de39dd..23384fb1d 100644 --- a/tests/status/ignore.c +++ b/tests/status/ignore.c @@ -1077,3 +1077,81 @@ void test_status_ignore__negate_starstar(void) cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config")); cl_assert_equal_i(0, ignored); } + +void test_status_ignore__ignore_all_toplevel_dirs_include_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/README.md", + "empty_standard_repo/src/main.c", + "empty_standard_repo/src/foo/foo.c", + "empty_standard_repo/dist/foo.o", + "empty_standard_repo/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/.gitignore", + "/*/\n" + "!/src\n"); + + assert_is_ignored("dist/foo.o"); + assert_is_ignored("dist/main.o"); + + refute_is_ignored("README.md"); + refute_is_ignored("src/foo.c"); + refute_is_ignored("src/foo/foo.c"); +} + +void test_status_ignore__subdir_ignore_all_toplevel_dirs_include_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/project/README.md", + "empty_standard_repo/project/src/main.c", + "empty_standard_repo/project/src/foo/foo.c", + "empty_standard_repo/project/dist/foo.o", + "empty_standard_repo/project/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/project/.gitignore", + "/*/\n" + "!/src\n"); + + assert_is_ignored("project/dist/foo.o"); + assert_is_ignored("project/dist/main.o"); + + refute_is_ignored("project/src/foo.c"); + refute_is_ignored("project/src/foo/foo.c"); + refute_is_ignored("project/README.md"); +} + +void test_status_ignore__subdir_ignore_everything_except_certain_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/project/README.md", + "empty_standard_repo/project/some_file", + "empty_standard_repo/project/src/main.c", + "empty_standard_repo/project/src/foo/foo.c", + "empty_standard_repo/project/dist/foo.o", + "empty_standard_repo/project/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/project/.gitignore", + "/*\n" + "!/src\n" + "!README.md\n"); + + assert_is_ignored("project/some_file"); + assert_is_ignored("project/dist/foo.o"); + assert_is_ignored("project/dist/main.o"); + + refute_is_ignored("project/README.md"); + refute_is_ignored("project/src/foo.c"); + refute_is_ignored("project/src/foo/foo.c"); +}