Commit 916fcbd61754f74b350ca689e27563cdbded2d30

Russell Belfer 2014-04-18T14:42:40

Fix ignore difference from git with trailing /* Ignore patterns that ended with a trailing '/*' were still needing to match against another actual '/' character in the full path. This is not the same behavior as core Git. Instead, we strip a trailing '/*' off of any patterns that were matching and just take it to imply the FNM_LEADING_DIR behavior.

diff --git a/src/attr_file.c b/src/attr_file.c
index 8a8d86a..57b4da7 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -353,6 +353,8 @@ bool git_attr_fnmatch__match(
 
 	if (match->flags & GIT_ATTR_FNMATCH_ICASE)
 		flags |= FNM_CASEFOLD;
+	if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
+		flags |= FNM_LEADING_DIR;
 
 	if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) {
 		filename = path->path;
@@ -543,6 +545,13 @@ int git_attr_fnmatch__parse(
 		if (--slash_count <= 0)
 			spec->flags = spec->flags & ~GIT_ATTR_FNMATCH_FULLPATH;
 	}
+	if (spec->length >= 2 &&
+		pattern[spec->length - 1] == '*' &&
+		pattern[spec->length - 2] == '/') {
+		spec->length -= 2;
+		spec->flags = spec->flags | GIT_ATTR_FNMATCH_LEADINGDIR;
+		/* leave FULLPATH match on, however */
+	}
 
 	if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 &&
 		context != NULL && git_path_root(pattern) < 0)
diff --git a/src/attr_file.h b/src/attr_file.h
index c906be4..09afa5b 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -30,6 +30,7 @@
 #define GIT_ATTR_FNMATCH_MATCH_ALL	(1U << 8)
 #define GIT_ATTR_FNMATCH_ALLOWNEG   (1U << 9)
 #define GIT_ATTR_FNMATCH_ALLOWMACRO (1U << 10)
+#define GIT_ATTR_FNMATCH_LEADINGDIR (1U << 11)
 
 #define GIT_ATTR_FNMATCH__INCOMING \
 	(GIT_ATTR_FNMATCH_ALLOWSPACE | \
diff --git a/tests/status/ignore.c b/tests/status/ignore.c
index 15c85e2..d88b2eb 100644
--- a/tests/status/ignore.c
+++ b/tests/status/ignore.c
@@ -456,6 +456,24 @@ void test_status_ignore__contained_dir_with_matching_name(void)
 	cl_assert_equal_i(0, counts.wrong_sorted_path);
 }
 
+void test_status_ignore__trailing_slash_star(void)
+{
+	static const char *test_files[] = {
+		"empty_standard_repo/file",
+		"empty_standard_repo/subdir/file",
+		"empty_standard_repo/subdir/sub2/sub3/file",
+		NULL
+	};
+
+	make_test_data("empty_standard_repo", test_files);
+	cl_git_mkfile(
+		"empty_standard_repo/subdir/.gitignore", "/**/*\n");
+
+	refute_is_ignored("file");
+	assert_is_ignored("subdir/sub2/sub3/file");
+	assert_is_ignored("subdir/file");
+}
+
 void test_status_ignore__adding_internal_ignores(void)
 {
 	g_repo = cl_git_sandbox_init("empty_standard_repo");