Add flag --no-require-git to always respect gitignore files

Summary: Currently, `--ignore-vcs` only serves to unset `--no-ignore-vcs`.
There is currently no way to tell fd to respect gitignore files when not in a
git repository.  This commit adds the flag `--no-require-git` to make fd always
respect all gitignore files.

This behaves the same as the `--no-require-git` option in [ripgrep](3bb71b0cb8/crates/core/app.rs (L2214-L2226))

This commit also contains an unrelated wording fix to CONTRIBUTING.md

Test Plan: `tests/tests.rs`

Background: I am using [Sapling](https://sapling-scm.com/docs/introduction/)
for working with git repositories (including this commit ☺️).  Since Sapling
uses `.sl` instead of `.git`, tools using the `ignore` crate (rg and fd) would show gitignored files.
I made a patch (ebf17eef22)
to `ignore` to respect gitignores with _either_ `.git` or `.sl`.  However,
@BurntSushi said he did not want to merge that patch and instead suggested I
use `--no-require-git` (https://github.com/BurntSushi/ripgrep/issues/2374).
This works fine, but I couldn't use this workaround for my other favorite tool!
That's what this patch is for 😁

(a follow-up patch will add a similar `FD_CONFIG_PATH` environment variable
like `RG_CONFIG_PATH`)
This commit is contained in:
Max 👨🏽‍💻 Coplan 2023-01-13 13:52:05 -08:00
parent ab7d5eff87
commit 08c0d427bf
7 changed files with 88 additions and 2 deletions

View file

@ -2,6 +2,8 @@
## Features
- Add flag --no-require-git to always respect gitignore files, see #1216 (@vegerot)
## Bugfixes
- Fix logic for when to use global ignore file. There was a bug where the only case where the

View file

@ -13,11 +13,11 @@ give us the chance to discuss any potential changes first.
## Add an entry to the changelog
If your contribution changes the behavior of `fd` (as opposed to a typo-fix
in the documentation), please update the [`CHANGELOG.md`](CHANGELOG.md) file
in the documentation), please update the [`CHANGELOG.md`](CHANGELOG.md#upcoming-release) file
and describe your changes. This makes the release process much easier and
therefore helps to get your changes into a new `fd` release faster.
The top of the `CHANGELOG` contains a *"unreleased"* section with a few
The top of the `CHANGELOG` contains an *"Upcoming release"* section with a few
subsections (Features, Bugfixes, …). Please add your entry to the subsection
that best describes your change.

View file

@ -74,6 +74,28 @@ pub struct Opts {
#[arg(long, overrides_with = "no_ignore_vcs", hide = true, action = ArgAction::SetTrue)]
ignore_vcs: (),
/// Do not require a git repository to respect gitignores.
/// By default, fd will only respect global gitignore rules, .gitignore rules,
/// and local exclude rules if fd detects that you are searching inside a
/// git repository. This flag allows you to relax this restriction such that
/// fd 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.
#[arg(
long,
overrides_with = "require_git",
hide_short_help = true,
// same description as ripgrep's flag: ripgrep/crates/core/app.rs
long_help
)]
pub no_require_git: bool,
/// Overrides --no-require-git
#[arg(long, overrides_with = "no_require_git", hide = true, action = ArgAction::SetTrue)]
require_git: (),
/// Show search results from files and directories that would otherwise be
/// ignored by '.gitignore', '.ignore', or '.fdignore' files in parent directories.
#[arg(

View file

@ -30,6 +30,9 @@ pub struct Config {
/// Whether to respect VCS ignore files (`.gitignore`, ..) or not.
pub read_vcsignore: bool,
/// Whether to require a `.git` directory to respect gitignore files.
pub require_git_to_read_vcsignore: bool,
/// Whether to respect the global ignore file or not.
pub read_global_ignore: bool,

View file

@ -239,6 +239,7 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
ignore_hidden: !(opts.hidden || opts.rg_alias_ignore()),
read_fdignore: !(opts.no_ignore || opts.rg_alias_ignore()),
read_vcsignore: !(opts.no_ignore || opts.rg_alias_ignore() || opts.no_ignore_vcs),
require_git_to_read_vcsignore: !opts.no_require_git,
read_parent_ignore: !opts.no_ignore_parent,
read_global_ignore: !(opts.no_ignore
|| opts.rg_alias_ignore()

View file

@ -77,6 +77,7 @@ pub fn scan(paths: &[PathBuf], patterns: Arc<Vec<Regex>>, config: Arc<Config>) -
.git_ignore(config.read_vcsignore)
.git_global(config.read_vcsignore)
.git_exclude(config.read_vcsignore)
.require_git(config.require_git_to_read_vcsignore)
.overrides(overrides)
.follow_links(config.follow_links)
// No need to check for supported platforms, option is unavailable on unsupported ones

View file

@ -808,6 +808,62 @@ fn test_custom_ignore_precedence() {
te.assert_output(&["--no-ignore", "foo"], "inner/foo");
}
/// Don't require git to respect gitignore (--no-require-git)
#[test]
fn test_respect_ignore_files() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// Not in a git repo anymore
fs::remove_dir(te.test_root().join(".git")).unwrap();
// don't respect gitignore because we're not in a git repo
te.assert_output(
&["foo"],
"a.foo
gitignored.foo
one/b.foo
one/two/c.foo
one/two/C.Foo2
one/two/three/d.foo
one/two/three/directory_foo/",
);
// respect gitignore because we set `--no-require-git`
te.assert_output(
&["--no-require-git", "foo"],
"a.foo
one/b.foo
one/two/c.foo
one/two/C.Foo2
one/two/three/d.foo
one/two/three/directory_foo/",
);
// make sure overriding works
te.assert_output(
&["--no-require-git", "--require-git", "foo"],
"a.foo
gitignored.foo
one/b.foo
one/two/c.foo
one/two/C.Foo2
one/two/three/d.foo
one/two/three/directory_foo/",
);
te.assert_output(
&["--no-require-git", "--no-ignore", "foo"],
"a.foo
gitignored.foo
fdignored.foo
one/b.foo
one/two/c.foo
one/two/C.Foo2
one/two/three/d.foo
one/two/three/directory_foo/",
);
}
/// VCS ignored files (--no-ignore-vcs)
#[test]
fn test_no_ignore_vcs() {
@ -2365,6 +2421,7 @@ fn test_number_parsing_errors() {
#[test_case("--hidden", &["--no-hidden"] ; "hidden")]
#[test_case("--no-ignore", &["--ignore"] ; "no-ignore")]
#[test_case("--no-ignore-vcs", &["--ignore-vcs"] ; "no-ignore-vcs")]
#[test_case("--no-require-git", &["--require-git"] ; "no-require-git")]
#[test_case("--follow", &["--no-follow"] ; "follow")]
#[test_case("--absolute-path", &["--relative-path"] ; "absolute-path")]
#[test_case("-u", &["--ignore", "--no-hidden"] ; "u")]