Skip to content

Commit 33065b6

Browse files
committed
feat!: empty pathspecs with prefix now are optionally matching the prefix.
Otherwise it's not possible to have the 'no pattern matches everything' case which is important in conjunction with prefixes and the requirement to still see everything outside of the prefix.
1 parent abfc6fd commit 33065b6

File tree

6 files changed

+26
-8
lines changed

6 files changed

+26
-8
lines changed

gix/src/dirwalk.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub struct Options {
1717
emit_empty_directories: bool,
1818
classify_untracked_bare_repositories: bool,
1919
emit_collapsed: Option<CollapsedEntriesEmissionMode>,
20-
pub(crate) use_prefix: bool,
20+
pub(crate) empty_patterns_match_prefix: bool,
2121
}
2222

2323
/// Construction
@@ -35,7 +35,7 @@ impl Options {
3535
emit_empty_directories: false,
3636
classify_untracked_bare_repositories: false,
3737
emit_collapsed: None,
38-
use_prefix: false,
38+
empty_patterns_match_prefix: false,
3939
}
4040
}
4141
}
@@ -59,12 +59,13 @@ impl From<Options> for gix_dir::walk::Options {
5959
}
6060

6161
impl Options {
62-
/// If `true`, default `false`, pathspecs and the directory walk itself will be setup to use the [prefix](crate::Repository::prefix).
62+
/// If `true`, default `false`, pathspecs and the directory walk itself will be setup to use the [prefix](crate::Repository::prefix)
63+
/// if patterns are empty.
6364
///
6465
/// This means that the directory walk will be limited to only what's inside the [repository prefix](crate::Repository::prefix).
6566
/// By default, the directory walk will see everything.
66-
pub fn use_prefix(mut self, toggle: bool) -> Self {
67-
self.use_prefix = toggle;
67+
pub fn empty_patterns_match_prefix(mut self, toggle: bool) -> Self {
68+
self.empty_patterns_match_prefix = toggle;
6869
self
6970
}
7071
/// If `toggle` is `true`, we will stop figuring out if any directory that is a candidate for recursion is also a nested repository,

gix/src/pathspec.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ impl<'repo> Pathspec<'repo> {
3232
/// be used to control where attributes are coming from.
3333
/// If `inherit_ignore_case` is `true`, the pathspecs may have their ignore-case default overridden to be case-insensitive by default.
3434
/// This only works towards turning ignore-case for pathspecs on, but won't ever turn that setting off if.
35+
/// If `empty_patterns_match_prefix` is `true`, then even empty patterns will match only what's inside of the prefix. Otherwise
36+
/// they will match everything.
3537
///
3638
/// ### Deviation
3739
///
3840
/// Pathspecs can declare to be case-insensitive as part of their elements, which is a setting that is now respected for attribute
3941
/// queries as well.
4042
pub fn new(
4143
repo: &'repo Repository,
44+
empty_patterns_match_prefix: bool,
4245
patterns: impl IntoIterator<Item = impl AsRef<BStr>>,
4346
inherit_ignore_case: bool,
4447
make_attributes: impl FnOnce() -> Result<gix_worktree::Stack, Box<dyn std::error::Error + Send + Sync + 'static>>,
@@ -49,9 +52,14 @@ impl<'repo> Pathspec<'repo> {
4952
.map(move |p| parse(p.as_ref(), defaults))
5053
.collect::<Result<Vec<_>, _>>()?;
5154
let needs_cache = patterns.iter().any(|p| !p.attributes.is_empty());
55+
let prefix = if patterns.is_empty() && !empty_patterns_match_prefix {
56+
None
57+
} else {
58+
repo.prefix()?
59+
};
5260
let search = Search::from_specs(
5361
patterns,
54-
repo.prefix()?,
62+
prefix,
5563
&gix_path::realpath_opts(
5664
repo.work_dir().unwrap_or_else(|| repo.git_dir()),
5765
repo.options.current_dir_or_empty(),

gix/src/repository/dirwalk.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ impl Repository {
6464
crate::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
6565
)?;
6666
let mut pathspec = self.pathspec(
67+
options.empty_patterns_match_prefix, /* empty patterns match prefix */
6768
patterns,
6869
true, /* inherit ignore case */
6970
index,
@@ -99,7 +100,7 @@ impl Repository {
99100
},
100101
excludes: Some(&mut excludes.inner),
101102
objects: &self.objects,
102-
explicit_traversal_root: (!options.use_prefix).then_some(workdir),
103+
explicit_traversal_root: (!options.empty_patterns_match_prefix).then_some(workdir),
103104
},
104105
options.into(),
105106
delegate,

gix/src/repository/pathspec.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,21 @@ impl Repository {
88
/// (but also note that `git` does not do that).
99
/// `index` may be needed to load attributes which is required only if `patterns` refer to attributes via `:(attr:…)` syntax.
1010
/// In the same vein, `attributes_source` affects where `.gitattributes` files are read from if pathspecs need to match against attributes.
11+
/// If `empty_patterns_match_prefix` is `true`, then even empty patterns will match only what's inside of the prefix. Otherwise
12+
/// they will match everything.
1113
///
1214
/// It will be initialized exactly how it would, and attribute matching will be conducted by reading the worktree first if available.
1315
/// If that is not desirable, consider calling [`Pathspec::new()`] directly.
1416
#[doc(alias = "Pathspec", alias = "git2")]
1517
pub fn pathspec(
1618
&self,
19+
empty_patterns_match_prefix: bool,
1720
patterns: impl IntoIterator<Item = impl AsRef<BStr>>,
1821
inherit_ignore_case: bool,
1922
index: &gix_index::State,
2023
attributes_source: gix_worktree::stack::state::attributes::Source,
2124
) -> Result<Pathspec<'_>, crate::pathspec::init::Error> {
22-
Pathspec::new(self, patterns, inherit_ignore_case, || {
25+
Pathspec::new(self, empty_patterns_match_prefix, patterns, inherit_ignore_case, || {
2326
self.attributes_only(index, attributes_source)
2427
.map(AttributeStack::detach)
2528
.map_err(Into::into)

gix/src/worktree/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ pub mod pathspec {
219219
/// Configure pathspecs `patterns` to be matched against, with pathspec attributes read from the worktree and then from the index
220220
/// if needed.
221221
///
222+
/// Note that the `empty_patterns_match_prefix` flag of the [parent method](crate::Repository::pathspec()) defaults to `true`.
223+
///
222224
/// ### Deviation
223225
///
224226
/// Pathspec attributes match case-insensitively by default if the underlying filesystem is configured that way.
@@ -244,6 +246,7 @@ pub mod pathspec {
244246
.map_err(|err| Error::Init(crate::pathspec::init::Error::Defaults(err.into())))?
245247
.unwrap_or(gitoxide::Pathspec::INHERIT_IGNORE_CASE_DEFAULT);
246248
Ok(self.parent.pathspec(
249+
true, /* empty patterns match prefix */
247250
patterns,
248251
inherit_ignore_case,
249252
&index,

gix/tests/repository/pathspec.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ fn defaults_are_taken_from_repo_config() -> crate::Result {
99
repo.config_snapshot_mut()
1010
.set_value(&gitoxide::Pathspec::ICASE, "true")?;
1111
let inherit_ignore_case = true;
12+
let empty_pathspecs_match_prefix = true;
1213
let mut pathspec = repo.pathspec(
14+
empty_pathspecs_match_prefix,
1315
[
1416
"hi",
1517
":!hip",

0 commit comments

Comments
 (0)