summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-07-07 13:27:27 +0200
committerPatrick Steinhardt <ps@pks.im>2017-08-25 18:00:34 +0200
commitb8922fc8f4a903b8c40614852e87bae07454f295 (patch)
treec9e65c60b6e14079020be442e8487693579ab85c
parent4467543ea76a59b1e10f20028da7779050f4953f (diff)
downloadlibgit2-b8922fc8f4a903b8c40614852e87bae07454f295.tar.gz
ignore: keep negative rules containing wildcards
Ignore rules allow for reverting a previously ignored rule by prefixing it with an exclamation mark. As such, a negative rule can only override previously ignored files. While computing all ignore patterns, we try to use this fact to optimize away some negative rules which do not override any previous patterns, as they won't change the outcome anyway. In some cases, though, this optimization causes us to get the actual ignores wrong for some files. This may happen whenever the pattern contains a wildcard, as we are unable to reason about whether a pattern overrides a previous pattern in a sane way. This happens for example in the case where a gitignore file contains "*.c" and "!src/*.c", where we wouldn't un-ignore files inside of the "src/" subdirectory. In this case, the first solution coming to mind may be to just strip the "src/" prefix and simply compare the basenames. While that would work here, it would stop working as soon as the basename pattern itself is different, like for example with "*x.c" and "!src/*.c. As such, we settle for the easier fix of just not optimizing away rules that contain a wildcard.
-rw-r--r--src/ignore.c10
-rw-r--r--tests/attr/ignore.c9
2 files changed, 17 insertions, 2 deletions
diff --git a/src/ignore.c b/src/ignore.c
index f42f625eb..61a94f33a 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -205,8 +205,14 @@ static int parse_ignore_file(
scan = git__next_line(scan);
- /* if a negative match doesn't actually do anything, throw it away */
- if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE)
+ /*
+ * If a negative match doesn't actually do anything,
+ * throw it away. As we cannot always verify whether a
+ * rule containing wildcards negates another rule, we
+ * do not optimize away these rules, though.
+ * */
+ if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE
+ && !(match->flags & GIT_ATTR_FNMATCH_HASWILD))
error = does_negate_rule(&valid_rule, &attrs->rules, match);
if (!error && valid_rule)
diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c
index a089ee408..5adfaf557 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -303,3 +303,12 @@ void test_attr_ignore__test(void)
assert_is_ignored(true, "dist/foo.o");
assert_is_ignored(true, "bin/foo");
}
+
+void test_attr_ignore__unignore_dir_succeeds(void)
+{
+ cl_git_rewritefile("attr/.gitignore",
+ "*.c\n"
+ "!src/*.c\n");
+ assert_is_ignored(false, "src/foo.c");
+ assert_is_ignored(true, "src/foo/foo.c");
+}