gitignore: don't apply patterns to parent directories
If you create a `dir/.gitignore` file with pattern "dir" in it, it'll
currently match the parent directory, making e.g. the `dir/.gitignore`
file itself ignored. That was quite confusing, and it doesn't match
how Git behaves. This patch fixes the bug.
@@ -83,11 +83,10 @@ impl GitIgnoreLine {
is_rooted |= input.contains('/');
let mut regex = String::new();
- if is_rooted {
- regex.insert_str(0, prefix);
- regex.insert(0, '^');
- } else {
- regex.insert_str(0, "(^|/)");
+ regex.push('^');
+ regex.push_str(prefix);
+ if !is_rooted {
+ regex.push_str("(.*/)?");
}
let components = input.split('/').collect_vec();
@@ -271,11 +270,19 @@ mod tests {
let file = GitIgnoreFile::empty().chain("dir/", b"foo\n").ok().unwrap();
// I consider it undefined whether a file in a parent directory matches, but
// let's test it anyway
- assert!(file.matches_file("foo"));
+ assert!(!file.matches_file("foo"));
assert!(file.matches_file("dir/foo"));
assert!(file.matches_file("dir/subdir/foo"));
}
+ #[test]
+ fn test_gitignore_pattern_same_as_prefix() {
+ let file = GitIgnoreFile::empty().chain("dir/", b"dir\n").ok().unwrap();
+ assert!(file.matches_file("dir/dir"));
+ // We don't want the "dir" pattern to apply to the parent directory
+ assert!(!file.matches_file("dir/foo"));
+ }
+
#[test]
fn test_gitignore_rooted_literal() {
let file = GitIgnoreFile::empty().chain("", b"/foo\n").ok().unwrap();
