Skip to content

Commit 9863d75

Browse files
committed
feat: add gix clean --patterns-for-entries|-m to help with wildcards.
1 parent 1a26732 commit 9863d75

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed

gitoxide-core/src/repository/clean.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub struct Options {
1515
pub precious: bool,
1616
pub directories: bool,
1717
pub repositories: bool,
18+
pub pathspec_matches_result: bool,
1819
pub skip_hidden_repositories: Option<FindRepository>,
1920
pub find_untracked_repositories: FindRepository,
2021
}
@@ -46,6 +47,7 @@ pub(crate) mod function {
4647
repositories,
4748
skip_hidden_repositories,
4849
find_untracked_repositories,
50+
pathspec_matches_result,
4951
}: Options,
5052
) -> anyhow::Result<()> {
5153
if format != OutputFormat::Human {
@@ -56,6 +58,7 @@ pub(crate) mod function {
5658
};
5759

5860
let index = repo.index_or_empty()?;
61+
let pathspec_for_dirwalk = !pathspec_matches_result;
5962
let has_patterns = !patterns.is_empty();
6063
let mut collect = InterruptableCollect::default();
6164
let collapse_directories = CollapseDirectory;
@@ -76,9 +79,29 @@ pub(crate) mod function {
7679
.emit_ignored(Some(collapse_directories))
7780
.empty_patterns_match_prefix(true)
7881
.emit_empty_directories(true);
79-
repo.dirwalk(&index, patterns, options, &mut collect)?;
80-
let prefix = repo.prefix()?.unwrap_or(Path::new(""));
82+
repo.dirwalk(
83+
&index,
84+
if pathspec_for_dirwalk {
85+
patterns.clone()
86+
} else {
87+
Vec::new()
88+
},
89+
options,
90+
&mut collect,
91+
)?;
8192

93+
let mut pathspec = pathspec_matches_result
94+
.then(|| {
95+
repo.pathspec(
96+
true,
97+
patterns,
98+
true,
99+
&index,
100+
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
101+
)
102+
})
103+
.transpose()?;
104+
let prefix = repo.prefix()?.unwrap_or(Path::new(""));
82105
let entries = collect.inner.into_entries_by_path();
83106
let mut entries_to_clean = 0;
84107
let mut skipped_directories = 0;
@@ -101,9 +124,14 @@ pub(crate) mod function {
101124
continue;
102125
}
103126

104-
let pathspec_includes_entry = entry
105-
.pathspec_match
106-
.map_or(false, |m| m != gix::dir::entry::PathspecMatch::Excluded);
127+
let pathspec_includes_entry = match pathspec.as_mut() {
128+
None => entry
129+
.pathspec_match
130+
.map_or(false, |m| m != gix::dir::entry::PathspecMatch::Excluded),
131+
Some(pathspec) => pathspec
132+
.pattern_matching_relative_path(entry.rela_path.as_bstr(), entry.disk_kind.map(|k| k.is_dir()))
133+
.map_or(false, |m| !m.is_excluded()),
134+
};
107135
pruned_entries += usize::from(!pathspec_includes_entry);
108136
if !pathspec_includes_entry && debug {
109137
writeln!(err, "DBG: prune '{}'", entry.rela_path).ok();
@@ -114,7 +142,7 @@ pub(crate) mod function {
114142

115143
let keep = match entry.status {
116144
Status::Pruned => {
117-
unreachable!("BUG: assumption that pruned entries have no pathspec match, but probably not")
145+
unreachable!("BUG: we skipped these above")
118146
}
119147
Status::Tracked => {
120148
unreachable!("BUG: tracked aren't emitted")

src/plumbing/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub fn main() -> Result<()> {
155155
directories,
156156
pathspec,
157157
repositories,
158+
pathspec_matches_result,
158159
skip_hidden_repositories,
159160
find_untracked_repositories,
160161
}) => prepare_and_run(
@@ -178,6 +179,7 @@ pub fn main() -> Result<()> {
178179
precious,
179180
directories,
180181
repositories,
182+
pathspec_matches_result,
181183
skip_hidden_repositories: skip_hidden_repositories.map(Into::into),
182184
find_untracked_repositories: find_untracked_repositories.into(),
183185
},

src/plumbing/options/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,12 @@ pub mod clean {
521521
/// Remove nested repositories.
522522
#[arg(long, short = 'r')]
523523
pub repositories: bool,
524+
/// Pathspec patterns are used to match the result of the dirwalk, not the dirwalk itself.
525+
///
526+
/// Use this if there is trouble using wildcard pathspecs, which affect the directory walk
527+
/// in reasonable, but often unexpected ways.
528+
#[arg(long, short = 'm')]
529+
pub pathspec_matches_result: bool,
524530
/// Enter ignored directories to skip repositories contained within.
525531
#[arg(long)]
526532
pub skip_hidden_repositories: Option<FindRepository>,

0 commit comments

Comments
 (0)