| #!/bin/sh | |
| test_description='Test handling of the current working directory becoming empty' | |
| . ./test-lib.sh | |
| test_expect_success setup ' | |
| test_commit init && | |
| git branch fd_conflict && | |
| mkdir -p foo/bar && | |
| test_commit foo/bar/baz && | |
| git revert HEAD && | |
| git tag reverted && | |
| git checkout fd_conflict && | |
| mkdir dirORfile && | |
| test_commit dirORfile/foo && | |
| git rm -r dirORfile && | |
| echo not-a-directory >dirORfile && | |
| git add dirORfile && | |
| git commit -m dirORfile && | |
| git switch -c df_conflict HEAD~1 && | |
| test_commit random_file && | |
| git switch -c undo_fd_conflict fd_conflict && | |
| git revert HEAD | |
| ' | |
| test_incidental_dir_removal () { | |
| test_when_finished "git reset --hard" && | |
| git checkout foo/bar/baz^{commit} && | |
| test_path_is_dir foo/bar && | |
| ( | |
| cd foo && | |
| "$@" && | |
| # Make sure foo still exists, and commands needing it work | |
| test-tool getcwd && | |
| git status --porcelain | |
| ) && | |
| test_path_is_missing foo/bar/baz && | |
| test_path_is_missing foo/bar && | |
| test_path_is_dir foo | |
| } | |
| test_required_dir_removal () { | |
| git checkout df_conflict^{commit} && | |
| test_when_finished "git clean -fdx" && | |
| ( | |
| cd dirORfile && | |
| # Ensure command refuses to run | |
| test_must_fail "$@" 2>../error && | |
| grep "Refusing to remove.*current working directory" ../error && | |
| # ...and that the index and working tree are left clean | |
| git diff --exit-code HEAD && | |
| # Ensure that getcwd and git status do not error out (which | |
| # they might if the current working directory had been removed) | |
| test-tool getcwd && | |
| git status --porcelain | |
| ) && | |
| test_path_is_dir dirORfile | |
| } | |
| test_expect_success 'checkout does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git checkout init | |
| ' | |
| test_expect_success 'checkout fails if cwd needs to be removed' ' | |
| test_required_dir_removal git checkout fd_conflict | |
| ' | |
| test_expect_success 'reset --hard does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git reset --hard init | |
| ' | |
| test_expect_success 'reset --hard fails if cwd needs to be removed' ' | |
| test_required_dir_removal git reset --hard fd_conflict | |
| ' | |
| test_expect_success 'merge does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git merge reverted | |
| ' | |
| # This file uses some simple merges where | |
| # Base: 'dirORfile/' exists | |
| # Side1: random other file changed | |
| # Side2: 'dirORfile/' removed, 'dirORfile' added | |
| # this should resolve cleanly, but merge-recursive throws merge conflicts | |
| # because it's dumb. Add a special test for checking merge-recursive (and | |
| # merge-ort), then after this just hard require ort for all remaining tests. | |
| # | |
| test_expect_success 'merge fails if cwd needs to be removed; recursive friendly' ' | |
| git checkout foo/bar/baz && | |
| test_when_finished "git clean -fdx" && | |
| mkdir dirORfile && | |
| ( | |
| cd dirORfile && | |
| test_must_fail git merge fd_conflict 2>../error | |
| ) && | |
| test_path_is_dir dirORfile && | |
| test_grep "Refusing to remove the current working directory" error | |
| ' | |
| test_expect_success 'merge fails if cwd needs to be removed' ' | |
| test_required_dir_removal git merge fd_conflict | |
| ' | |
| test_expect_success 'cherry-pick does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git cherry-pick reverted | |
| ' | |
| test_expect_success 'cherry-pick fails if cwd needs to be removed' ' | |
| test_required_dir_removal git cherry-pick fd_conflict | |
| ' | |
| test_expect_success 'rebase does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git rebase reverted | |
| ' | |
| test_expect_success 'rebase fails if cwd needs to be removed' ' | |
| test_required_dir_removal git rebase fd_conflict | |
| ' | |
| test_expect_success 'revert does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git revert HEAD | |
| ' | |
| test_expect_success 'revert fails if cwd needs to be removed' ' | |
| test_required_dir_removal git revert undo_fd_conflict | |
| ' | |
| test_expect_success 'rm does not clean cwd incidentally' ' | |
| test_incidental_dir_removal git rm bar/baz.t | |
| ' | |
| test_expect_success 'apply does not remove cwd incidentally' ' | |
| git diff HEAD HEAD~1 >patch && | |
| test_incidental_dir_removal git apply ../patch | |
| ' | |
| test_incidental_untracked_dir_removal () { | |
| test_when_finished "git reset --hard" && | |
| git checkout foo/bar/baz^{commit} && | |
| mkdir -p untracked && | |
| mkdir empty | |
| >untracked/random && | |
| ( | |
| cd untracked && | |
| "$@" && | |
| # Make sure untracked still exists, and commands needing it work | |
| test-tool getcwd && | |
| git status --porcelain | |
| ) && | |
| test_path_is_missing empty && | |
| test_path_is_missing untracked/random && | |
| test_path_is_dir untracked | |
| } | |
| test_expect_success 'clean does not remove cwd incidentally' ' | |
| test_incidental_untracked_dir_removal \ | |
| git -C .. clean -fd -e warnings . >warnings && | |
| test_grep "Refusing to remove current working directory" warnings | |
| ' | |
| test_expect_success 'stash does not remove cwd incidentally' ' | |
| test_incidental_untracked_dir_removal \ | |
| git stash --include-untracked | |
| ' | |
| test_expect_success '`rm -rf dir` only removes a subset of dir' ' | |
| test_when_finished "rm -rf a/" && | |
| mkdir -p a/b/c && | |
| >a/b/c/untracked && | |
| >a/b/c/tracked && | |
| git add a/b/c/tracked && | |
| ( | |
| cd a/b && | |
| git rm -rf ../b | |
| ) && | |
| test_path_is_dir a/b && | |
| test_path_is_missing a/b/c/tracked && | |
| test_path_is_file a/b/c/untracked | |
| ' | |
| test_expect_success '`rm -rf dir` even with only tracked files will remove something else' ' | |
| test_when_finished "rm -rf a/" && | |
| mkdir -p a/b/c && | |
| >a/b/c/tracked && | |
| git add a/b/c/tracked && | |
| ( | |
| cd a/b && | |
| git rm -rf ../b | |
| ) && | |
| test_path_is_missing a/b/c/tracked && | |
| test_path_is_missing a/b/c && | |
| test_path_is_dir a/b | |
| ' | |
| test_expect_success 'git version continues working from a deleted dir' ' | |
| mkdir tmp && | |
| ( | |
| cd tmp && | |
| rm -rf ../tmp && | |
| git version | |
| ) | |
| ' | |
| test_submodule_removal () { | |
| path_status=$1 && | |
| shift && | |
| test_status= | |
| test "$path_status" = dir && test_status=test_must_fail | |
| test_when_finished "git reset --hard HEAD~1" && | |
| test_when_finished "rm -rf .git/modules/my_submodule" && | |
| git checkout foo/bar/baz && | |
| git init my_submodule && | |
| touch my_submodule/file && | |
| git -C my_submodule add file && | |
| git -C my_submodule commit -m "initial commit" && | |
| git submodule add ./my_submodule && | |
| git commit -m "Add the submodule" && | |
| ( | |
| cd my_submodule && | |
| $test_status "$@" | |
| ) && | |
| test_path_is_${path_status} my_submodule | |
| } | |
| test_expect_success 'rm -r with -C leaves submodule if cwd inside' ' | |
| test_submodule_removal dir git -C .. rm -r my_submodule/ | |
| ' | |
| test_expect_success 'rm -r leaves submodule if cwd inside' ' | |
| test_submodule_removal dir \ | |
| git --git-dir=../.git --work-tree=.. rm -r ../my_submodule/ | |
| ' | |
| test_expect_success 'rm -rf removes submodule even if cwd inside' ' | |
| test_submodule_removal missing \ | |
| git --git-dir=../.git --work-tree=.. rm -rf ../my_submodule/ | |
| ' | |
| test_done |