Commit 82e929a88bc79dc5ebd9a8484a40319ac6768c9b

Edward Thomson 2017-06-04T19:35:39

Merge pull request #4239 from roblg/toplevel-dir-ignore-fix Fix issue with directory glob ignore in subdirectories

diff --git a/src/attr_file.c b/src/attr_file.c
index 0bb761d..e30ea5e 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 3a19389..a089ee4 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 251de39..23384fb 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");
+}