summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rwxr-xr-xci/test_complete.sh2
-rw-r--r--complete/_rg3
-rw-r--r--ignore/src/dir.rs33
-rw-r--r--ignore/src/walk.rs10
-rw-r--r--src/app.rs23
-rw-r--r--src/args.rs1
-rw-r--r--tests/feature.rs28
8 files changed, 100 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 95cf28d2..e72d48af 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,8 @@ Feature enhancements:
Add `--include-zero` flag that shows files searched without matches.
* [FEATURE #1390](https://github.com/BurntSushi/ripgrep/pull/1390):
Add `--no-context-separator` flag that always hides context separators.
+* [FEATURE #1414](https://github.com/BurntSushi/ripgrep/pull/1414):
+ Add `--no-require-git` flag to allow ripgrep to respect gitignores anywhere.
* [FEATURE #1420](https://github.com/BurntSushi/ripgrep/pull/1420):
Add `--no-ignore-exclude` to disregard rules in `.git/info/exclude` files.
diff --git a/ci/test_complete.sh b/ci/test_complete.sh
index 985ef11b..0268de89 100755
--- a/ci/test_complete.sh
+++ b/ci/test_complete.sh
@@ -44,7 +44,7 @@ main() {
# Occasionally we may have to handle some manually, however
help_args=( ${(f)"$(
$rg --help |
- $rg -i -- '^\s+--?[a-z0-9]|--[imnp]' |
+ $rg -i -- '^\s+--?[a-z0-9]|--[a-z]' |
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9]|--[a-z0-9-]+)\\b' |
$rg -v -- --print0 | # False positives
sort -u
diff --git a/complete/_rg b/complete/_rg
index b90d1801..82dc3cdb 100644
--- a/complete/_rg
+++ b/complete/_rg
@@ -144,6 +144,8 @@ _rg() {
+ '(ignore-vcs)' # VCS ignore-file options
"--no-ignore-vcs[don't respect version control ignore files]"
$no'--ignore-vcs[respect version control ignore files]'
+ "--no-require-git[don't require git repository to respect gitignore rules]"
+ $no'--require-git[require git repository to respect gitignore rules]'
+ '(ignore-dot)' # .ignore-file options
"--no-ignore-dot[don't respect .ignore files]"
@@ -284,6 +286,7 @@ _rg() {
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
$no"--no-context-separator[don't print context separators]"
'--debug[show debug messages]'
+ '--trace[show more verbose debug messages]'
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)'
"(1 stats)--files[show each file that would be searched (but don't search)]"
'*--ignore-file=[specify additional ignore file]:ignore file:_files'
diff --git a/ignore/src/dir.rs b/ignore/src/dir.rs
index cf957891..3f4d10bb 100644
--- a/ignore/src/dir.rs
+++ b/ignore/src/dir.rs
@@ -78,6 +78,9 @@ struct IgnoreOptions {
git_exclude: bool,
/// Whether to ignore files case insensitively
ignore_case_insensitive: bool,
+ /// Whether a git repository must be present in order to apply any
+ /// git-related ignore rules.
+ require_git: bool,
}
/// Ignore is a matcher useful for recursively walking one or more directories.
@@ -385,7 +388,9 @@ impl Ignore {
Match::None,
Match::None,
);
- let any_git = self.parents().any(|ig| ig.0.has_git);
+ let any_git =
+ !self.0.opts.require_git
+ || self.parents().any(|ig| ig.0.has_git);
let mut saw_git = false;
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() {
@@ -537,6 +542,7 @@ impl IgnoreBuilder {
git_ignore: true,
git_exclude: true,
ignore_case_insensitive: false,
+ require_git: true,
},
}
}
@@ -686,6 +692,16 @@ impl IgnoreBuilder {
self
}
+ /// Whether a git repository is required to apply git-related ignore
+ /// rules (global rules, .gitignore and local exclude rules).
+ ///
+ /// When disabled, git-related ignore rules are applied even when searching
+ /// outside a git repository.
+ pub fn require_git(&mut self, yes: bool) -> &mut IgnoreBuilder {
+ self.opts.require_git = yes;
+ self
+ }
+
/// Process ignore files case insensitively
///
/// This is disabled by default.
@@ -883,6 +899,21 @@ mod tests {
}
#[test]
+ fn gitignore_allowed_no_git() {
+ let td = tmpdir();
+ wfile(td.path().join(".gitignore"), "foo\n!bar");
+
+ let (ig, err) = IgnoreBuilder::new()
+ .require_git(false)
+ .build()
+ .add_child(td.path());
+ assert!(err.is_none());
+ assert!(ig.matched("foo", false).is_ignore());
+ assert!(ig.matched("bar", false).is_whitelist());
+ assert!(ig.matched("baz", false).is_none());
+ }
+
+ #[test]
fn ignore() {
let td = tmpdir();
wfile(td.path().join(".ignore"), "foo\n!bar");
diff --git a/ignore/src/walk.rs b/ignore/src/walk.rs
index bbe6d7d7..331268a3 100644
--- a/ignore/src/walk.rs
+++ b/ignore/src/walk.rs
@@ -780,6 +780,16 @@ impl WalkBuilder {
self
}
+ /// Whether a git repository is required to apply git-related ignore
+ /// rules (global rules, .gitignore and local exclude rules).
+ ///
+ /// When disabled, git-related ignore rules are applied even when searching
+ /// outside a git repository.
+ pub fn require_git(&mut self, yes: bool) -> &mut WalkBuilder {
+ self.ig_builder.require_git(yes);
+ self
+ }
+
/// Process ignore files case insensitively
///
/// This is disabled by default.
diff --git a/src/app.rs b/src/app.rs
index 94e8a421..320261b5 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -602,6 +602,7 @@ pub fn all_args_and_flags() -> Vec<RGArg> {
flag_no_ignore_vcs(&mut args);
flag_no_messages(&mut args);
flag_no_pcre2_unicode(&mut args);
+ flag_no_require_git(&mut args);
flag_null(&mut args);
flag_null_data(&mut args);
flag_one_file_system(&mut args);
@@ -1928,6 +1929,28 @@ This flag can be disabled with --pcre2-unicode.
args.push(arg);
}
+fn flag_no_require_git(args: &mut Vec<RGArg>) {
+ const SHORT: &str = "Do not require a git repository to use gitignores.";
+ const LONG: &str = long!("\
+By default, ripgrep will only respect global gitignore rules, .gitignore rules
+and local exclude rules if ripgrep detects that you are searching inside a
+git repository. This flag allows you to relax this restriction such that
+ripgrep will respect all git related ignore rules regardless of whether you're
+searching in a git repository or not.
+
+This flag can be disabled with --require-git.
+");
+ let arg = RGArg::switch("no-require-git")
+ .help(SHORT).long_help(LONG)
+ .overrides("require-git");
+ args.push(arg);
+
+ let arg = RGArg::switch("require-git")
+ .hidden()
+ .overrides("no-require-git");
+ args.push(arg);
+}
+
fn flag_null(args: &mut Vec<RGArg>) {
const SHORT: &str = "Print a NUL byte after file paths.";
const LONG: &str = long!("\
diff --git a/src/args.rs b/src/args.rs
index a322c55b..d9eeb2e1 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -882,6 +882,7 @@ impl ArgMatches {
.git_global(!self.no_ignore_vcs() && !self.no_ignore_global())
.git_ignore(!self.no_ignore_vcs())
.git_exclude(!self.no_ignore_vcs() && !self.no_ignore_exclude())
+ .require_git(!self.is_present("no-require-git"))
.ignore_case_insensitive(self.ignore_file_case_insensitive());
if !self.no_ignore() {
builder.add_custom_ignore_filename(".rgignore");
diff --git a/tests/feature.rs b/tests/feature.rs
index 33ab4e17..3d61f459 100644
--- a/tests/feature.rs
+++ b/tests/feature.rs
@@ -728,6 +728,34 @@ rgtest!(f1207_ignore_encoding, |dir: Dir, mut cmd: TestCommand| {
eqnice!("\u{FFFD}\u{FFFD}\x00b\n", cmd.stdout());
});
+// See: https://github.com/BurntSushi/ripgrep/issues/1414
+rgtest!(f1414_no_require_git, |dir: Dir, mut cmd: TestCommand| {
+ dir.create(".gitignore", "foo");
+ dir.create("foo", "");
+ dir.create("bar", "");
+
+ let stdout = cmd.args(&[
+ "--sort", "path",
+ "--files",
+ ]).stdout();
+ eqnice!("bar\nfoo\n", stdout);
+
+ let stdout = cmd.args(&[
+ "--sort", "path",
+ "--files",
+ "--no-require-git",
+ ]).stdout();
+ eqnice!("bar\n", stdout);
+
+ let stdout = cmd.args(&[
+ "--sort", "path",
+ "--files",
+ "--no-require-git",
+ "--require-git",
+ ]).stdout();
+ eqnice!("bar\nfoo\n", stdout);
+});
+
// See: https://github.com/BurntSushi/ripgrep/pull/1420
rgtest!(f1420_no_ignore_dot, |dir: Dir, mut cmd: TestCommand| {
dir.create_dir(".git/info");