Skip to content

Commit 31e795a

Browse files
committed
fix: Assure that worktrees in hidden directories are not deleted (#1470)
1 parent 2bacc45 commit 31e795a

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

gix-dir/src/walk/classify.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,17 @@ pub fn path(
265265
),
266266
);
267267
}
268-
if kind.map_or(false, |d| d.is_recursable_dir()) && out.pathspec_match.is_none() {
269-
// we have patterns that didn't match at all, *yet*. We want to look inside.
268+
if kind.map_or(false, |d| d.is_recursable_dir())
269+
&& (out.pathspec_match.is_none()
270+
|| worktree_relative_worktree_dirs.map_or(false, |worktrees| {
271+
for_deletion.is_some()
272+
&& worktrees
273+
.iter()
274+
.any(|dir| dir.starts_with_str(&*rela_path) && dir.get(rela_path.len()) == Some(&b'/'))
275+
}))
276+
{
277+
// We have patterns that didn't match at all, *yet*, or there are contained worktrees.
278+
// We want to look inside.
270279
out.pathspec_match = Some(PathspecMatch::Prefix);
271280
}
272281
}

gix-dir/tests/fixtures/many.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ git clone dir-with-tracked-file in-repo-worktree
448448
git clone dir-with-tracked-file in-repo-hidden-worktree
449449
(cd in-repo-hidden-worktree
450450
echo '/hidden/' > .gitignore
451-
mkdir -p hidden/sbudir
451+
mkdir -p hidden/subdir
452+
touch hidden/file
452453
git worktree add -b worktree-branch hidden/subdir/worktree
453454
)

gix-dir/tests/walk/mod.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4579,6 +4579,7 @@ fn in_repo_hidden_worktree() -> crate::Result {
45794579
&root,
45804580
ctx,
45814581
walk::Options {
4582+
for_deletion: None,
45824583
worktree_relative_worktree_dirs: Some(&BTreeSet::from(["hidden/subdir/worktree".into()])),
45834584
..options_emit_all()
45844585
},
@@ -4601,7 +4602,48 @@ fn in_repo_hidden_worktree() -> crate::Result {
46014602
entry("dir/file", Tracked, File),
46024603
entry("hidden", Ignored(Expendable), Directory),
46034604
],
4604-
"Currently, worktrees can't be found in ignored directories, even though hit should"
4605+
"Without the intend to delete, the worktree remains hidden, which is what we want to see in a `status` for example"
46054606
);
4607+
4608+
for ignored_emission_mode in [Matching, CollapseDirectory] {
4609+
for deletion_mode in [
4610+
ForDeletionMode::IgnoredDirectoriesCanHideNestedRepositories,
4611+
ForDeletionMode::FindRepositoriesInIgnoredDirectories,
4612+
ForDeletionMode::FindNonBareRepositoriesInIgnoredDirectories,
4613+
] {
4614+
let ((out, _root), entries) = collect(&root, None, |keep, ctx| {
4615+
walk(
4616+
&root,
4617+
ctx,
4618+
walk::Options {
4619+
emit_ignored: Some(ignored_emission_mode),
4620+
for_deletion: Some(deletion_mode),
4621+
worktree_relative_worktree_dirs: Some(&BTreeSet::from(["hidden/subdir/worktree".into()])),
4622+
..options_emit_all()
4623+
},
4624+
keep,
4625+
)
4626+
});
4627+
assert_eq!(
4628+
out,
4629+
walk::Outcome {
4630+
read_dir_calls: 4,
4631+
returned_entries: entries.len(),
4632+
seen_entries: 5,
4633+
}
4634+
);
4635+
assert_eq!(
4636+
entries,
4637+
&[
4638+
entry_nokind(".git", Pruned).with_property(DotGit).with_match(Always),
4639+
entry(".gitignore", Untracked, File),
4640+
entry("dir/file", Tracked, File),
4641+
entry("hidden/file", Ignored(Expendable), File),
4642+
entry("hidden/subdir/worktree", Tracked, Repository).no_index_kind(),
4643+
],
4644+
"Worktrees within hidden directories are also detected and protected by counting them as tracked (like submodules)"
4645+
);
4646+
}
4647+
}
46064648
Ok(())
46074649
}

0 commit comments

Comments
 (0)