From 8b09cf254e8e376907b9e26d172cb9adf98f4d6e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 25 Jul 2024 20:08:13 +0200 Subject: [PATCH 1/3] prepare manual release of `gitoxide-core` (#1466) --- Cargo.lock | 2 +- Cargo.toml | 2 +- gitoxide-core/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c82c1ef45d0..4dc241d1671 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1248,7 +1248,7 @@ dependencies = [ [[package]] name = "gitoxide-core" -version = "0.39.0" +version = "0.39.1" dependencies = [ "anyhow", "async-io 2.2.2", diff --git a/Cargo.toml b/Cargo.toml index 38ee898d9d4..4dc1037437a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -168,7 +168,7 @@ gitoxide-core-async-client = ["gitoxide-core/async-client", "futures-lite"] [dependencies] anyhow = "1.0.42" -gitoxide-core = { version = "^0.39.0", path = "gitoxide-core" } +gitoxide-core = { version = "^0.39.1", path = "gitoxide-core" } gix-features = { version = "^0.38.2", path = "gix-features" } gix = { version = "^0.64.0", path = "gix", default-features = false } time = "0.3.23" diff --git a/gitoxide-core/Cargo.toml b/gitoxide-core/Cargo.toml index 65dab5c037a..7f947de992f 100644 --- a/gitoxide-core/Cargo.toml +++ b/gitoxide-core/Cargo.toml @@ -2,7 +2,7 @@ name = "gitoxide-core" description = "The library implementing all capabilities of the gitoxide CLI" repository = "https://github.com/Byron/gitoxide" -version = "0.39.0" +version = "0.39.1" authors = ["Sebastian Thiel "] license = "MIT OR Apache-2.0" edition = "2021" From 2bacc45f794d300656ca770c803a63c5df8b71fc Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 26 Jul 2024 09:46:00 +0200 Subject: [PATCH 2/3] Add a test to see what happens if worktrees are hidden in ignored directories (#1469) --- gix-dir/tests/fixtures/many.sh | 9 +++++- gix-dir/tests/walk/mod.rs | 55 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/gix-dir/tests/fixtures/many.sh b/gix-dir/tests/fixtures/many.sh index a83e902100e..5f22234ec90 100755 --- a/gix-dir/tests/fixtures/many.sh +++ b/gix-dir/tests/fixtures/many.sh @@ -443,4 +443,11 @@ git clone dir-with-tracked-file in-repo-worktree (cd in-repo-worktree git worktree add worktree git worktree add -b other-worktree dir/worktree -) \ No newline at end of file +) + +git clone dir-with-tracked-file in-repo-hidden-worktree +(cd in-repo-hidden-worktree + echo '/hidden/' > .gitignore + mkdir -p hidden/sbudir + git worktree add -b worktree-branch hidden/subdir/worktree +) diff --git a/gix-dir/tests/walk/mod.rs b/gix-dir/tests/walk/mod.rs index cb5412977f2..748c6baef2e 100644 --- a/gix-dir/tests/walk/mod.rs +++ b/gix-dir/tests/walk/mod.rs @@ -4550,3 +4550,58 @@ fn in_repo_worktree() -> crate::Result { ); Ok(()) } + +#[test] +fn in_repo_hidden_worktree() -> crate::Result { + let root = fixture("in-repo-hidden-worktree"); + let ((out, _root), entries) = collect(&root, None, |keep, ctx| walk(&root, ctx, options_emit_all(), keep)); + assert_eq!( + out, + walk::Outcome { + read_dir_calls: 2, + returned_entries: entries.len(), + seen_entries: 4, + } + ); + assert_eq!( + entries, + &[ + entry_nokind(".git", Pruned).with_property(DotGit).with_match(Always), + entry(".gitignore", Untracked, File), + entry("dir/file", Tracked, File), + entry("hidden", Ignored(Expendable), Directory), + ], + "if worktree information isn't provided, they would not be discovered in hidden directories" + ); + + let ((out, _root), entries) = collect(&root, None, |keep, ctx| { + walk( + &root, + ctx, + walk::Options { + worktree_relative_worktree_dirs: Some(&BTreeSet::from(["hidden/subdir/worktree".into()])), + ..options_emit_all() + }, + keep, + ) + }); + assert_eq!( + out, + walk::Outcome { + read_dir_calls: 2, + returned_entries: entries.len(), + seen_entries: 4, + } + ); + assert_eq!( + entries, + &[ + entry_nokind(".git", Pruned).with_property(DotGit).with_match(Always), + entry(".gitignore", Untracked, File), + entry("dir/file", Tracked, File), + entry("hidden", Ignored(Expendable), Directory), + ], + "Currently, worktrees can't be found in ignored directories, even though hit should" + ); + Ok(()) +} From 31e795abf27dea8fd7dd7f59996cdd5d70398601 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 26 Jul 2024 10:27:18 +0200 Subject: [PATCH 3/3] fix: Assure that worktrees in hidden directories are not deleted (#1470) --- gix-dir/src/walk/classify.rs | 13 ++++++++-- gix-dir/tests/fixtures/many.sh | 3 ++- gix-dir/tests/walk/mod.rs | 44 +++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/gix-dir/src/walk/classify.rs b/gix-dir/src/walk/classify.rs index a93e7c0b16a..b87c893e7c7 100644 --- a/gix-dir/src/walk/classify.rs +++ b/gix-dir/src/walk/classify.rs @@ -265,8 +265,17 @@ pub fn path( ), ); } - if kind.map_or(false, |d| d.is_recursable_dir()) && out.pathspec_match.is_none() { - // we have patterns that didn't match at all, *yet*. We want to look inside. + if kind.map_or(false, |d| d.is_recursable_dir()) + && (out.pathspec_match.is_none() + || worktree_relative_worktree_dirs.map_or(false, |worktrees| { + for_deletion.is_some() + && worktrees + .iter() + .any(|dir| dir.starts_with_str(&*rela_path) && dir.get(rela_path.len()) == Some(&b'/')) + })) + { + // We have patterns that didn't match at all, *yet*, or there are contained worktrees. + // We want to look inside. out.pathspec_match = Some(PathspecMatch::Prefix); } } diff --git a/gix-dir/tests/fixtures/many.sh b/gix-dir/tests/fixtures/many.sh index 5f22234ec90..e5146933644 100755 --- a/gix-dir/tests/fixtures/many.sh +++ b/gix-dir/tests/fixtures/many.sh @@ -448,6 +448,7 @@ git clone dir-with-tracked-file in-repo-worktree git clone dir-with-tracked-file in-repo-hidden-worktree (cd in-repo-hidden-worktree echo '/hidden/' > .gitignore - mkdir -p hidden/sbudir + mkdir -p hidden/subdir + touch hidden/file git worktree add -b worktree-branch hidden/subdir/worktree ) diff --git a/gix-dir/tests/walk/mod.rs b/gix-dir/tests/walk/mod.rs index 748c6baef2e..057271e0968 100644 --- a/gix-dir/tests/walk/mod.rs +++ b/gix-dir/tests/walk/mod.rs @@ -4579,6 +4579,7 @@ fn in_repo_hidden_worktree() -> crate::Result { &root, ctx, walk::Options { + for_deletion: None, worktree_relative_worktree_dirs: Some(&BTreeSet::from(["hidden/subdir/worktree".into()])), ..options_emit_all() }, @@ -4601,7 +4602,48 @@ fn in_repo_hidden_worktree() -> crate::Result { entry("dir/file", Tracked, File), entry("hidden", Ignored(Expendable), Directory), ], - "Currently, worktrees can't be found in ignored directories, even though hit should" + "Without the intend to delete, the worktree remains hidden, which is what we want to see in a `status` for example" ); + + for ignored_emission_mode in [Matching, CollapseDirectory] { + for deletion_mode in [ + ForDeletionMode::IgnoredDirectoriesCanHideNestedRepositories, + ForDeletionMode::FindRepositoriesInIgnoredDirectories, + ForDeletionMode::FindNonBareRepositoriesInIgnoredDirectories, + ] { + let ((out, _root), entries) = collect(&root, None, |keep, ctx| { + walk( + &root, + ctx, + walk::Options { + emit_ignored: Some(ignored_emission_mode), + for_deletion: Some(deletion_mode), + worktree_relative_worktree_dirs: Some(&BTreeSet::from(["hidden/subdir/worktree".into()])), + ..options_emit_all() + }, + keep, + ) + }); + assert_eq!( + out, + walk::Outcome { + read_dir_calls: 4, + returned_entries: entries.len(), + seen_entries: 5, + } + ); + assert_eq!( + entries, + &[ + entry_nokind(".git", Pruned).with_property(DotGit).with_match(Always), + entry(".gitignore", Untracked, File), + entry("dir/file", Tracked, File), + entry("hidden/file", Ignored(Expendable), File), + entry("hidden/subdir/worktree", Tracked, Repository).no_index_kind(), + ], + "Worktrees within hidden directories are also detected and protected by counting them as tracked (like submodules)" + ); + } + } Ok(()) }