BurntSushi/ripgrep

Inconsistent behavior with negation pattern in `.gitignore`

Nadrieril opened this issue · 8 comments

Please tick this box to confirm you have reviewed the above.

  • I have a different issue.

What version of ripgrep are you using?

ripgrep 13.0.0
-SIMD -AVX (compiled)
+SIMD +AVX (runtime)

How did you install ripgrep?

Using nix

What operating system are you using ripgrep on?

NixOS 23.11

Describe your bug.

See below. Feels related to #1050 but I think they're different.

What are the steps to reproduce the behavior?

Make a repo with:

.gitignore

build/
!/some_dir/build/

some_dir/build/foo

string

What is the actual behavior?

> rg -l string
some_dir/build/foo
> rg -l string some_dir
# nothing
> rg -l string some_dir/build
some_dir/build/foo

What is the expected behavior?

rg -l string some_dir should find the file too.

Please try the latest release of ripgrep.

Oh, sorry, that appears to be fixed in 14.0

Ah nope, still a bug but it requires one more level of nesting:

ripgrep 14.1.0

features:-simd-accel,-pcre2
simd(compile):+SSE2,-SSSE3,-AVX2
simd(runtime):+SSE2,+SSSE3,+AVX2

PCRE2 is not available in this build of ripgrep.

.gitignore

build/
!/some_dir/subdir/build/

some_dir/subdir/build/foo

string

What is the actual behavior?

> rg -l string
some_dir/subdir/build/foo
> rg -l string some_dir
# nothing
> rg -l string some_dir/subdir
some_dir/subdir/build/foo
> rg -l string some_dir/subdir/build
some_dir/subdir/build/foo

I can reproduce this with the ignore crate directly and

use ignore::Walk;
fn main() {
    for result in Walk::new("./some_dir") {
        match result {
            Ok(entry) => println!("{}", entry.path().display()),
            Err(err) => println!("ERROR: {}", err),
        }
    }
}

(with the CWD in the directory with the .gitignore)

This is probably a duplicate of an existing bug, but they are difficult to find.

There are several open issues related to gitignore support that I don't plan on fixing until I've had a chance to rethink the ignore crate from first principles. It might happen within the next year.

I found a similar bug when using wildcards in .gitignore. Let me know, if I should open a new issue.

Script to reproduce the bug:

#!/usr/bin/env sh

mkdir -p bug/foo/bar && cd bug
git init
echo "baz" > foo/bar/baz.txt
echo "/foo/bar/baz*.txt" > .gitignore

rg -l baz
# Output:
# rg: No files were searched, which means ripgrep probably applied a filter you didn't expect.
# Running with --debug will show why files are being skipped.

rg -l baz foo/
# Output:
# foo/bar/baz.txt

Version:

ripgrep 14.1.0

features:-simd-accel,+pcre2
simd(compile):+SSE2,-SSSE3,-AVX2
simd(runtime):+SSE2,+SSSE3,+AVX2

PCRE2 10.42 is available (JIT is available)

Actually, I just realized that the wildcard isn't even needed. The bug is reproducible with a .gitignore containing /foo/bar/baz.txt (see script in my previous comment).

It may be worth looking at https://github.com/Byron/gitoxide/tree/main/gix-ignore when refactoring, or somehow pulling in the logic from it as a library.