'git clean -fd' must not delete an untracked directory if it belongs
to a different Git repository or worktree.  Unfortunately, if a
'.gitignore' rule in the outer repository happens to match a file in a
nested repository or worktree, then something goes awry and 'git clean
-fd' does delete the content of the nested repository's worktree
except that ignored file, potentially leading to data loss.

Add a test to 't7300-clean.sh' to demonstrate this breakage.

This issue is a regression introduced in 6b1db43109 (clean: teach
clean -d to preserve ignored paths, 2017-05-23).

Signed-off-by: SZEDER Gábor <szeder....@gmail.com>
---

BEWARE: Our toplevel '.gitignore' currently contains the '*.manifest'
rule [1], which ignores the file 'compat/win32/git.manifest' [2], so
if you use nested worktrees in your git repo, then a 'git clean -fd'
will delete them.

[1] 516dfb8416 (.gitignore: touch up the entries regarding Visual
    Studio, 2019-07-29)
[2] fe90397604 (mingw: embed a manifest to trick UAC into Doing The
    Right Thing, 2019-06-27)


 t/t7300-clean.sh | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index a2c45d1902..d01fd120ab 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -669,6 +669,28 @@ test_expect_success 'git clean -d skips untracked dirs 
containing ignored files'
        test_path_is_missing foo/b/bb
 '
 
+test_expect_failure 'git clean -d skips nested repo containing ignored files' '
+       test_when_finished "rm -rf nested-repo-with-ignored-file" &&
+
+       git init nested-repo-with-ignored-file &&
+       (
+               cd nested-repo-with-ignored-file &&
+               >file &&
+               git add file &&
+               git commit -m Initial &&
+
+               # This file is ignored by a .gitignore rule in the outer repo
+               # added in the previous test.
+               >ignoreme
+       ) &&
+
+       git clean -fd &&
+
+       test_path_is_file nested-repo-with-ignored-file/.git/index &&
+       test_path_is_file nested-repo-with-ignored-file/ignoreme &&
+       test_path_is_file nested-repo-with-ignored-file/file
+'
+
 test_expect_success MINGW 'handle clean & core.longpaths = false nicely' '
        test_config core.longpaths false &&
        a50=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
-- 
2.23.0.331.g4e51dcdf11

Reply via email to