Skip to content

Commit

Permalink
Add flag --no-require-git to always respect gitignore files
Browse files Browse the repository at this point in the history
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](https://github.com/BurntSushi/ripgrep/blob/3bb71b0cb8727ac43237af78ba5c707298de0128/crates/core/app.rs#L2214-L2226)

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 (vegerot/ripgrep@ebf17ee)
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` (BurntSushi/ripgrep#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`)
  • Loading branch information
vegerot committed Jan 3, 2023
1 parent 7c86c7d commit d10c05d
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,25 @@ 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.
#[arg(
long,
overrides_with = "require_git",
hide_short_help = true,
// same description as ripgrep's flag: ripgrep/crates/core/app.rs
long_help = "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.\n\n\
This flag can be disabled with --require-git."
)]
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(
Expand Down
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions src/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 56 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `--ignore-vcs`
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() {
Expand Down

0 comments on commit d10c05d

Please sign in to comment.