How ripgrep Ignore Precedence Rules Work: .gitignore vs .ignore vs .rgignore
ripgrep resolves ignore conflicts using a deterministic six-level precedence chain where command-line globs override custom ignore files (including .rgignore), which override .ignore files, which in turn override .gitignore files, with deeper directory rules always winning over parent directory rules within the same type.
When searching codebases with BurntSushi/ripgrep, understanding how the tool prioritizes conflicting ignore rules is essential for effective file exclusion. The precedence logic determines whether a .gitignore entry can be overridden by a local .ignore file or if a .rgignore pattern takes ultimate precedence. This article examines the exact hierarchy implemented in the ignore crate, referencing the specific source files that govern these rules.
The Six-Level Precedence Hierarchy
According to crates/ignore/src/walk.rs, ripgrep evaluates ignore sources in the following strict order, with each level capable of masking rules from lower levels.
1. Glob Overrides (Highest Priority)
Explicit --glob or --iglob patterns supplied on the command line are checked first. Whitelist globs (!pattern) immediately stop further matching and include the file, while ignore globs (pattern) cause the path to be skipped without consulting ignore files. This stage pre-empts all file-based ignore rules entirely.
2. Custom Ignore Files Including .rgignore
Files added via --ignore-file or the default .rgignore filename are processed next. As documented in walk.rs at lines 743-747, "These ignore files have higher precedence than all other ignore files." In crates/core/flags/hiargs.rs at line 905, ripgrep registers .rgignore as a custom ignore filename using builder.add_custom_ignore_filename(".rgignore");.
3. .ignore Files
Project-local .ignore files override all .gitignore files. The documentation in walk.rs lines 59-68 clarifies that "any .ignore file overrides all .gitignore files," making this the standard mechanism for repository-specific exclusions that should not be committed to Git.
4. .gitignore and Git-Specific Files
Standard Git ignore files are applied after .ignore, including repository .gitignore, <repo>/.git/info/exclude, and the global Git ignore file located at $XDG_CONFIG_HOME/git/ignore or $HOME/.config/git/ignore.
5. Programmatically Added Ignore Files
Ignore files added via the API using IgnoreBuilder::add_ignore receive the lowest precedence among ignore sources.
6. Directory Depth Within the Same Type
When multiple files of the same type exist in different directories (e.g., nested .ignore files), the more deeply nested file wins. As stated in walk.rs lines 66-68, the nested rule "has a higher precedence than less nested ignore files."
Practical Examples of Precedence in Action
The following scenarios demonstrate how ripgrep applies these rules when files contain conflicting patterns.
Overriding .gitignore with .ignore
Consider a project where you want to track a file in Git but exclude it from ripgrep searches, or vice versa:
project/
├── .gitignore (contains: secret.txt)
└── src/
├── .ignore (contains: !secret.txt)
└── secret.txt
Running rg secret.txt will find src/secret.txt because the .ignore file in src/ whitelists it. According to the precedence rules in walk.rs, the .ignore file at level 3 overrides the .gitignore at level 4.
Enforcing Rules with .rgignore
Because .rgignore is a custom ignore filename, it occupies precedence level 2, outranking both .ignore and .gitignore:
# .rgignore (repository root)
*.log
# Even if a .gitignore or .ignore explicitly whitelists debug.log,
# the .rgignore pattern wins and the file is omitted:
rg debug.log # -> no output
This makes .rgignore ideal for personal exclusions that must apply regardless of project-level ignore files.
Using --ignore-file for Temporary Rules
You can inject custom ignore files dynamically, which behave exactly like .rgignore:
# myrules.txt contains: *.bak
rg --ignore-file myrules.txt "function" .
The rules in myrules.txt take precedence over all built-in ignore files (.ignore, .gitignore) because --ignore-file maps to the custom ignore filename precedence level.
Summary
- Precedence is deterministic: ripgrep checks sources in the order: globs → custom files (
.rgignore) →.ignore→.gitignore→ API-added files. .rgignorewins over.gitignore: As a custom ignore filename,.rgignorepatterns override both.ignoreand.gitignoreentries..ignoreoverrides Git: Any.ignorefile takes precedence over all.gitignorefiles, making it suitable for search-specific exclusions.- Depth matters: Within the same file type, rules in deeper directories override parent directory rules.
- Command-line globs are king:
--globand--iglobflags bypass all file-based ignore logic entirely.
Frequently Asked Questions
Does .rgignore completely override .gitignore?
Yes. Because .rgignore is treated as a custom ignore filename in crates/core/flags/hiargs.rs, it occupies precedence level 2, while .gitignore sits at level 4. Any pattern in .rgignore will override conflicting rules in .gitignore or .ignore files.
Can I whitelist a file in .gitignore that is ignored by .rgignore?
No. Due to the precedence hierarchy, .rgignore (custom ignore) outranks .gitignore. Once a path matches a .rgignore pattern, ripgrep skips the file unless a command-line glob override (--glob) explicitly includes it at level 1.
What happens when both parent and child directories have .ignore files?
The child directory's .ignore file wins. Within the same ignore type, ripgrep applies the "closest" or most deeply nested rule, as implemented in the directory traversal logic in walk.rs lines 66-68.
How do I temporarily override all ignore files for a single search?
Use the --glob or --iglob flag with a whitelist pattern. Command-line globs are evaluated before any ignore files, making them the highest precedence mechanism for inclusion or exclusion according to the override logic in crates/ignore/src/overrides.rs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →