From 0407e104f611d623547897ca99d172673b31779f Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Wed, 8 Oct 2025 21:09:21 -0400 Subject: [PATCH] ignore: fix problem with searching whitelisted hidden files ... specifically, when the whitelist comes from a _parent_ gitignore file. Our handling of parent gitignores is pretty ham-fisted and has been a source of some unfortunate bugs. The problem is that we need to strip the parent path from the path we're searching in order to correctly apply the globs. But getting this stripping correct seems to be a subtle affair. Fixes #3173 --- CHANGELOG.md | 2 ++ crates/ignore/src/dir.rs | 24 ++++++++++++++---------- tests/regression.rs | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 075b997..23efcad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ Bug fixes: Ensure hyphens in flag names are escaped in the roff text for the man page. * [BUG #3155](https://github.com/BurntSushi/ripgrep/issues/3155): Statically compile PCRE2 into macOS release artifacts on `aarch64`. +* [BUG #3173](https://github.com/BurntSushi/ripgrep/issues/3173): + Fix ancestor ignore filter bug when searching whitelisted hidden files. Feature enhancements: diff --git a/crates/ignore/src/dir.rs b/crates/ignore/src/dir.rs index be4a9a3..8c1434a 100644 --- a/crates/ignore/src/dir.rs +++ b/crates/ignore/src/dir.rs @@ -467,16 +467,20 @@ impl Ignore { .take_while(|ig| !ig.0.is_absolute_parent) .last() .map_or(path, |ig| { - strip_if_is_prefix( - "/", - strip_if_is_prefix( - strip_if_is_prefix( - "./", - ig.0.dir.as_path(), - ), - path, - ), - ) + // This is a weird special case when ripgrep users + // search with just a `.`, as some tools do + // automatically (like consult). In this case, if + // we don't bail out now, the code below will strip + // a leading `.` from `path`, which might mangle + // a hidden file name! + if ig.0.dir.as_path() == Path::new(".") { + return path; + } + let without_dot_slash = + strip_if_is_prefix("./", ig.0.dir.as_path()); + let relative_base = + strip_if_is_prefix(without_dot_slash, path); + strip_if_is_prefix("/", relative_base) }), ); diff --git a/tests/regression.rs b/tests/regression.rs index 8dd1ba7..7f9818f 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -1586,3 +1586,24 @@ YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY\n \ eqnice!("test\n", got); } ); + +// See: https://github.com/BurntSushi/ripgrep/issues/3173 +rgtest!(r3173_hidden_whitelist_only_dot, |dir: Dir, _: TestCommand| { + dir.create_dir("subdir"); + dir.create("subdir/.foo.txt", "text"); + dir.create(".ignore", "!.foo.txt"); + + let cmd = || dir.command(); + eqnice!(cmd().args(&["--files"]).stdout(), "subdir/.foo.txt\n"); + eqnice!(cmd().args(&["--files", "."]).stdout(), "./subdir/.foo.txt\n"); + eqnice!(cmd().args(&["--files", "./"]).stdout(), "./subdir/.foo.txt\n"); + + let cmd = || { + let mut cmd = dir.command(); + cmd.current_dir(dir.path().join("subdir")); + cmd + }; + eqnice!(cmd().args(&["--files"]).stdout(), ".foo.txt\n"); + eqnice!(cmd().args(&["--files", "."]).stdout(), "./.foo.txt\n"); + eqnice!(cmd().args(&["--files", "./"]).stdout(), "./.foo.txt\n"); +});