git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Phillip Wood <phillip.wood123@gmail.com>
To: Elijah Newren via GitGitGadget <gitgitgadget@gmail.com>,
	git@vger.kernel.org
Cc: "Jeff King" <peff@peff.net>, "René Scharfe" <l.s.r@web.de>,
	"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
	"Elijah Newren" <newren@gmail.com>,
	"Glen Choo" <chooglen@google.com>,
	"Philip Oakley" <philipoakley@iee.email>
Subject: Re: [PATCH v3 00/11] Avoid removing the current working directory, even if it becomes empty
Date: Tue, 30 Nov 2021 11:04:32 +0000	[thread overview]
Message-ID: <8e8b95d7-a4b4-6839-c572-8a43bbae8e0c@gmail.com> (raw)
In-Reply-To: <pull.1140.v3.git.git.1637966463.gitgitgadget@gmail.com>

Hi Elijah

On 26/11/2021 22:40, Elijah Newren via GitGitGadget wrote:
> Traditionally, if folks run git commands such as checkout or rebase from a
> subdirectory, that git command could remove their current working directory
> and result in subsequent git and non-git commands either getting confused or
> printing messages that confuse the user (e.g. "fatal: Unable to read current
> working directory: No such file or directory"). Many commands either
> silently avoid removing directories that are not empty (i.e. those that have
> untracked or modified files in them)[1], or show an error and abort,
> depending on which is more appropriate for the command in question. With
> this series, we augment the reasons to avoid removing directories to include
> not just has-untracked-or-modified-files, but also to avoid removing the
> original_cwd as well.
> 
> Peff and Junio provided some good pros/cons, if it helps:
> 
>   * Pros: Peff (original suggester of the idea)[2], and Junio[3]
>   * Cons: Peff [2, again -- see the "P.S."], and Junio[4]
> 
> [1] well, with a few exceptions; see
> https://lore.kernel.org/git/pull.1036.v3.git.1632760428.gitgitgadget@gmail.com/
> [2] https://lore.kernel.org/git/YS8eEtwQvF7TaLCb@coredump.intra.peff.net/
> [3] https://lore.kernel.org/git/xmqqo86elyht.fsf@gitster.g/ [4]
> https://lore.kernel.org/git/xmqqo8691gr8.fsf@gitster.g/


Thanks for working on this, I'm sorry I haven't had time to take a 
proper look at it but I think it is a good idea. I did notice that 
you're using ":/" in patch 8 and wondered what happens if some runs 'git 
--literal-pathspecs stash' but I haven't looked properly.

Best Wishes

Phillip

> Changes since v2:
> 
>   * the series is now only about the working tree. So if the original cwd is
>     outside the worktree (or we're in a bare repo), then the new code is a
>     no-op.
>   * fixed ugly early die() possibility (uses strbuf_getcwd() instead of
>     xgetcwd())
>   * modified the initial tests to show both expected and desired behavior.
>     subsequent patches fix the tests. One new patch added at the end which
>     simplifies the tests to only check for desired behavior.
>   * NULLify startup_info->original_cwd when it matches the toplevel worktree;
>     that is already protected and we don't need secondary protection for it.
>     This simplified some other codepaths so we don't have to check for
>     startup_info->original_cwd == "".
>   * clarified some commit messages
> 
> Changes since v1:
> 
>   * clarified multiple commit messages
>   * renamed the_cwd to startup_info->original_cwd to make it clearer that
>     it's our parent process'es cwd that really matters, which we inherited at
>     program startup. Also pulls it out of the global namespace.
>   * Normalize the path for startup_info->original_cwd, and ensure that it's
>     actually the original cwd even if -C is passed to git.
>   * small code cleanups suggested by René and Ævar
>   * split the final patch, which got the most comments into two, one for each
>     function being modified; significantly extending the first of the two
>     commit messages with a lot of history
>   * no longer has a content conflict with so/stash-staged
>   * add another value for the flags parameter that remove_dir_recursively()
>     takes so that it can opt into either the old or the new behavior. Use
>     that for the one special corner case I could find where it matters, and
>     add a few tests around it to highlight the utility of the flag.
> 
> Elijah Newren (11):
>    t2501: add various tests for removing the current working directory
>    setup: introduce startup_info->original_cwd
>    unpack-trees: refuse to remove startup_info->original_cwd
>    unpack-trees: add special cwd handling
>    symlinks: do not include startup_info->original_cwd in dir removal
>    clean: do not attempt to remove startup_info->original_cwd
>    rebase: do not attempt to remove startup_info->original_cwd
>    stash: do not attempt to remove startup_info->original_cwd
>    dir: avoid incidentally removing the original_cwd in remove_path()
>    dir: new flag to remove_dir_recurse() to spare the original_cwd
>    t2501: simplify the tests since we can now assume desired behavior
> 
>   builtin/clean.c      |  44 +++++--
>   builtin/rm.c         |   3 +-
>   builtin/stash.c      |   5 +-
>   cache.h              |   2 +
>   common-main.c        |   4 +
>   dir.c                |  15 ++-
>   dir.h                |   9 +-
>   sequencer.c          |   3 +
>   setup.c              |  65 +++++++++++
>   symlinks.c           |   8 +-
>   t/t2501-cwd-empty.sh | 268 +++++++++++++++++++++++++++++++++++++++++++
>   unpack-trees.c       |  30 ++++-
>   unpack-trees.h       |   1 +
>   13 files changed, 435 insertions(+), 22 deletions(-)
>   create mode 100755 t/t2501-cwd-empty.sh
> 
> 
> base-commit: 88d915a634b449147855041d44875322de2b286d
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1140%2Fnewren%2Fcwd_removal-v3
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1140/newren/cwd_removal-v3
> Pull-Request: https://github.com/git/git/pull/1140
> 
> Range-diff vs v2:
> 
>    1:  38a120f5c03 !  1:  4b0044656b0 t2501: add various tests for removing the current working directory
>       @@ Metadata
>         ## Commit message ##
>            t2501: add various tests for removing the current working directory
>        
>       -    Numerous commands will remove empty working directories, especially if
>       -    they are in the way of placing needed files.  That is normally fine, but
>       -    removing the current working directory can cause confusion for the user
>       -    when they run subsequent commands.  For example, after one git process
>       -    has removed the current working directory, git status/log/diff will all
>       -    abort with the message:
>       +    Numerous commands will remove directories left empty as a "convenience"
>       +    after removing files within them.  That is normally fine, but removing
>       +    the current working directory can be rather inconvenient since it can
>       +    cause confusion for the user when they run subsequent commands.  For
>       +    example, after one git process has removed the current working
>       +    directory, git status/log/diff will all abort with the message:
>        
>                fatal: Unable to read current working directory: No such file or directory
>        
>       +    We also have code paths that, when a file needs to be placed where a
>       +    directory is (due to e.g. checkout, merge, reset, whatever), will check
>       +    if this is okay and error out if not.  These rules include:
>       +      * all tracked files under that directory are intended to be removed by
>       +        the operation
>       +      * none of the tracked files under that directory have uncommitted
>       +        modification
>       +      * there are no untracked files under that directory
>       +    However, if we end up remove the current working directory, we can cause
>       +    user confusion when they run subsequent commands, so we would prefer if
>       +    there was a fourth rule added to this list: avoid removing the current
>       +    working directory.
>       +
>            Since there are several code paths that can result in the current
>            working directory being removed, add several tests of various different
>       -    codepaths that check for the behavior we would instead like to see.
>       -    This include a number of new error messages that we will be adding in
>       -    subsequent commits as we implement the desired checks.
>       +    codepaths.  To make it clearer what the difference between the current
>       +    behavior and the behavior at the end of the series, code both of them
>       +    into the tests and have the appropriate behavior be selected by a flag.
>       +    Subsequent commits will toggle the flag from current to desired
>       +    behavior.
>       +
>       +    Also add a few tests suggested during the review of earlier rounds of
>       +    this patch series.
>        
>            Signed-off-by: Elijah Newren <newren@gmail.com>
>        
>       @@ t/t2501-cwd-empty.sh (new)
>        +
>        +test_expect_success setup '
>        +	test_commit init &&
>       -+	mkdir subdir &&
>       -+	test_commit subdir/file &&
>        +
>        +	git branch fd_conflict &&
>        +
>       @@ t/t2501-cwd-empty.sh (new)
>        +	git tag reverted &&
>        +
>        +	git checkout fd_conflict &&
>       -+	git rm subdir/file.t &&
>       ++	mkdir dirORfile &&
>       ++	test_commit dirORfile/foo &&
>       ++
>       ++	git rm -r dirORfile &&
>        +	echo not-a-directory >dirORfile &&
>        +	git add dirORfile &&
>       -+	git commit -m 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_expect_failure 'checkout does not clean cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       ++test_incidental_dir_removal () {
>       ++	works=$1 &&
>       ++	shift &&
>       ++
>       ++	test_when_finished "git reset --hard" &&
>       ++
>       ++	git checkout foo/bar/baz^{commit} &&
>        +	test_path_is_dir foo/bar &&
>        +
>        +	(
>        +		cd foo &&
>       -+		git checkout init &&
>       -+		cd ..
>       ++		"$@" &&
>       ++
>       ++		# Although we want pwd & git status to pass, test for existing
>       ++		# rather than desired behavior.
>       ++		if [[ $works == "success" ]]; then
>       ++			pwd -P &&
>       ++			git status --porcelain
>       ++		else
>       ++			! pwd -P &&
>       ++			test_might_fail git status --porcelain
>       ++		fi
>        +	) &&
>        +	test_path_is_missing foo/bar/baz &&
>        +	test_path_is_missing foo/bar &&
>       -+	test_path_is_dir foo
>       -+'
>        +
>       -+test_expect_failure 'checkout fails if cwd needs to be removed' '
>       -+	git checkout foo/bar/baz &&
>       ++	# Although we want dir to be present, test for existing rather
>       ++	# than desired behavior.
>       ++	if [[ $works == "success" ]]; then
>       ++		test_path_is_dir foo
>       ++	else
>       ++		test_path_is_missing foo
>       ++	fi
>       ++}
>       ++
>       ++test_required_dir_removal () {
>       ++	works=$1 &&
>       ++	shift &&
>       ++
>       ++	git checkout df_conflict^{commit} &&
>        +	test_when_finished "git clean -fdx" &&
>        +
>       -+	mkdir dirORfile &&
>        +	(
>        +		cd dirORfile &&
>        +
>       -+		test_must_fail git checkout fd_conflict 2>../error &&
>       -+		grep "Refusing to remove the current working directory" ../error
>       ++		# We'd like for the command to fail (much as it would if there
>       ++		# was an untracked file there), and for pwd & git status to
>       ++		# succeed afterwards.  But test for existing rather than
>       ++		# desired behavior.
>       ++		if [[ $works == "success" ]]; then
>       ++			test_must_fail "$@" 2>../error &&
>       ++			grep "Refusing to remove.*current working directory" ../error &&
>       ++			pwd -P &&
>       ++			git status --porcelain
>       ++		else
>       ++			"$@" &&
>       ++			! pwd -P &&
>       ++			test_might_fail git status --porcelain
>       ++		fi
>        +	) &&
>        +
>       -+	test_path_is_dir dirORfile
>       ++	# Although we want dirORfile to be present, test for existing rather
>       ++	# than desired behavior.
>       ++	if [[ $works == "success" ]]; then
>       ++		test_path_is_dir dirORfile
>       ++	else
>       ++		test_path_is_file dirORfile
>       ++	fi
>       ++}
>       ++
>       ++test_expect_success 'checkout does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git checkout init
>        +'
>        +
>       -+test_expect_failure 'reset --hard does not clean cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_path_is_dir foo/bar &&
>       ++test_expect_success 'checkout fails if cwd needs to be removed' '
>       ++	test_required_dir_removal failure git checkout fd_conflict
>       ++'
>        +
>       -+	(
>       -+		cd foo &&
>       -+		git reset --hard init &&
>       -+		cd ..
>       -+	) &&
>       -+	test_path_is_missing foo/bar/baz &&
>       -+	test_path_is_missing foo/bar &&
>       -+	test_path_is_dir foo
>       ++test_expect_success 'reset --hard does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git reset --hard init
>       ++'
>       ++
>       ++test_expect_success 'reset --hard fails if cwd needs to be removed' '
>       ++	test_required_dir_removal failure git reset --hard fd_conflict
>       ++'
>       ++
>       ++test_expect_success 'merge does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git merge reverted
>        +'
>        +
>       -+test_expect_failure 'reset --hard fails if cwd needs to be removed' '
>       ++# 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" &&
>        +
>       @@ t/t2501-cwd-empty.sh (new)
>        +	(
>        +		cd dirORfile &&
>        +
>       -+		test_must_fail git reset --hard fd_conflict 2>../error &&
>       -+		grep "Refusing to remove.*the current working directory" ../error
>       ++		# We would rather this failed, but we test for existing
>       ++		# rather than desired behavior
>       ++		git merge fd_conflict 2>../error
>        +	) &&
>        +
>       -+	test_path_is_dir dirORfile
>       ++	## Here is the behavior we would rather have:
>       ++	#test_path_is_dir dirORfile &&
>       ++	#grep "Refusing to remove the current working directory" error
>       ++	## But instead we test for existing behavior
>       ++	test_path_is_file dirORfile &&
>       ++	test_must_be_empty error
>        +'
>        +
>       -+test_expect_failure 'merge does not remove cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++GIT_TEST_MERGE_ALGORITHM=ort
>        +
>       -+	(
>       -+		cd subdir &&
>       -+		git merge fd_conflict
>       -+	) &&
>       ++test_expect_success 'merge fails if cwd needs to be removed' '
>       ++	test_required_dir_removal failure git merge fd_conflict
>       ++'
>        +
>       -+	test_path_is_missing subdir/file.t &&
>       -+	test_path_is_dir subdir
>       ++test_expect_success 'cherry-pick does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git cherry-pick reverted
>        +'
>        +
>       -+test_expect_failure 'merge fails if cwd needs to be removed' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++test_expect_success 'cherry-pick fails if cwd needs to be removed' '
>       ++	test_required_dir_removal failure git cherry-pick fd_conflict
>       ++'
>        +
>       -+	mkdir dirORfile &&
>       -+	(
>       -+		cd dirORfile &&
>       -+		test_must_fail git merge fd_conflict 2>../error &&
>       -+		grep "Refusing to remove the current working directory" ../error
>       -+	) &&
>       ++test_expect_success 'rebase does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git rebase reverted
>       ++'
>        +
>       -+	test_path_is_dir dirORfile
>       ++test_expect_success 'rebase fails if cwd needs to be removed' '
>       ++	test_required_dir_removal failure git rebase fd_conflict
>        +'
>        +
>       -+test_expect_failure 'cherry-pick does not remove cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++test_expect_success 'revert does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git revert HEAD
>       ++'
>        +
>       -+	(
>       -+		cd subdir &&
>       -+		git cherry-pick fd_conflict
>       -+	) &&
>       ++test_expect_success 'revert fails if cwd needs to be removed' '
>       ++	test_required_dir_removal failure git revert undo_fd_conflict
>       ++'
>        +
>       -+	test_path_is_missing subdir/file.t &&
>       -+	test_path_is_dir subdir
>       ++test_expect_success 'rm does not clean cwd incidentally' '
>       ++	test_incidental_dir_removal failure git rm bar/baz.t
>        +'
>        +
>       -+test_expect_failure 'cherry-pick fails if cwd needs to be removed' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++test_expect_success 'apply does not remove cwd incidentally' '
>       ++	git diff HEAD HEAD~1 >patch &&
>       ++	test_incidental_dir_removal failure git apply ../patch
>       ++'
>        +
>       -+	mkdir dirORfile &&
>       -+	(
>       -+		cd dirORfile &&
>       -+		test_must_fail git cherry-pick fd_conflict 2>../error &&
>       -+		grep "Refusing to remove the current working directory" ../error
>       -+	) &&
>       ++test_incidental_untracked_dir_removal () {
>       ++	works=$1 &&
>       ++	shift &&
>        +
>       -+	test_path_is_dir dirORfile
>       -+'
>       ++	test_when_finished "git reset --hard" &&
>        +
>       -+test_expect_failure 'rebase does not remove cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++	git checkout foo/bar/baz^{commit} &&
>       ++	mkdir -p untracked &&
>       ++	mkdir empty
>       ++	>untracked/random &&
>        +
>        +	(
>       -+		cd subdir &&
>       -+		git rebase foo/bar/baz fd_conflict
>       ++		cd untracked &&
>       ++		"$@" &&
>       ++
>       ++		# Although we want pwd & git status to pass, test for existing
>       ++		# rather than desired behavior.
>       ++		if [[ $works == "success" ]]; then
>       ++			pwd -P &&
>       ++			git status --porcelain
>       ++		else
>       ++			! pwd -P &&
>       ++			test_might_fail git status --porcelain
>       ++		fi
>        +	) &&
>       ++	test_path_is_missing empty &&
>       ++	test_path_is_missing untracked/random &&
>        +
>       -+	test_path_is_missing subdir/file.t &&
>       -+	test_path_is_dir subdir
>       ++	# Although we want dir to be present, test for existing rather
>       ++	# than desired behavior.
>       ++	if [[ $works == "success" ]]; then
>       ++		test_path_is_dir untracked
>       ++	else
>       ++		test_path_is_missing untracked
>       ++	fi
>       ++}
>       ++
>       ++test_expect_success 'clean does not remove cwd incidentally' '
>       ++	test_incidental_untracked_dir_removal failure \
>       ++		git -C .. clean -fd -e warnings . >warnings
>        +'
>        +
>       -+test_expect_failure 'rebase fails if cwd needs to be removed' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       -+
>       -+	mkdir dirORfile &&
>       -+	(
>       -+		cd dirORfile &&
>       -+		test_must_fail git rebase foo/bar/baz fd_conflict 2>../error &&
>       -+		grep "Refusing to remove the current working directory" ../error
>       -+	) &&
>       -+
>       -+	test_path_is_dir dirORfile
>       ++test_expect_success 'stash does not remove cwd incidentally' '
>       ++	test_incidental_untracked_dir_removal failure \
>       ++		git stash --include-untracked
>        +'
>        +
>       -+test_expect_failure 'revert does not remove cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++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 subdir &&
>       -+		git revert subdir/file
>       ++		cd a/b &&
>       ++		git rm -rf ../b
>        +	) &&
>        +
>       -+	test_path_is_missing subdir/file.t &&
>       -+	test_path_is_dir subdir
>       ++	test_path_is_dir a/b &&
>       ++	test_path_is_missing a/b/c/tracked &&
>       ++	test_path_is_file a/b/c/untracked
>        +'
>        +
>       -+test_expect_failure 'revert fails if cwd needs to be removed' '
>       -+	git checkout fd_conflict &&
>       -+	git revert HEAD &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++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 &&
>        +
>       -+	mkdir dirORfile &&
>        +	(
>       -+		cd dirORfile &&
>       -+		test_must_fail git revert HEAD 2>../error &&
>       -+		grep "Refusing to remove the current working directory" ../error
>       ++		cd a/b &&
>       ++		git rm -rf ../b
>        +	) &&
>        +
>       -+	test_path_is_dir dirORfile
>       ++	test_path_is_missing a/b/c/tracked &&
>       ++	## We would prefer if a/b was still present, though empty, since it
>       ++	## was the current working directory
>       ++	#test_path_is_dir a/b
>       ++	## But the current behavior is that it not only deletes the directory
>       ++	## a/b as requested, but also goes and deletes a
>       ++	test_path_is_missing a
>        +'
>        +
>       -+test_expect_failure 'rm does not remove cwd incidentally' '
>       -+	test_when_finished "git reset --hard" &&
>       -+	git checkout foo/bar/baz &&
>       -+
>       ++test_expect_success 'git version continues working from a deleted dir' '
>       ++	mkdir tmp &&
>        +	(
>       -+		cd foo &&
>       -+		git rm bar/baz.t
>       -+	) &&
>       -+
>       -+	test_path_is_missing foo/bar/baz &&
>       -+	test_path_is_missing foo/bar &&
>       -+	test_path_is_dir foo
>       ++		cd tmp &&
>       ++		rm -rf ../tmp &&
>       ++		git version
>       ++	)
>        +'
>        +
>       -+test_expect_failure 'apply does not remove cwd incidentally' '
>       -+	test_when_finished "git reset --hard" &&
>       -+	git checkout foo/bar/baz &&
>       ++test_submodule_removal () {
>       ++	path_status=$1 &&
>       ++	shift &&
>        +
>       -+	(
>       -+		cd subdir &&
>       -+		git diff subdir/file init | git apply
>       -+	) &&
>       ++	test_status=
>       ++	test $path_status = dir && test_status=test_must_fail
>        +
>       -+	test_path_is_missing subdir/file.t &&
>       -+	test_path_is_dir subdir
>       -+'
>       ++	# Actually, while path_status == dir && test_status=test_must_fail
>       ++	# reflect our desired behavior, current behavior is:
>       ++	path_status=missing
>       ++	test_status=
>       ++
>       ++	test_when_finished "git reset --hard HEAD~1" &&
>       ++	test_when_finished "rm -rf .git/modules/my_submodule" &&
>        +
>       -+test_expect_failure 'clean does not remove cwd incidentally' '
>        +	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>        +
>       -+	mkdir empty &&
>       -+	mkdir untracked &&
>       -+	>untracked/random &&
>       ++	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 untracked &&
>       -+		git clean -fd -e warnings :/ >../warnings &&
>       -+		grep "Refusing to remove current working directory" ../warnings
>       ++		cd my_submodule &&
>       ++		$test_status "$@"
>        +	) &&
>        +
>       -+	test_path_is_missing empty &&
>       -+	test_path_is_missing untracked/random &&
>       -+	test_path_is_dir untracked
>       -+'
>       ++	test_path_is_${path_status} my_submodule
>       ++}
>        +
>       -+test_expect_failure 'stash does not remove cwd incidentally' '
>       -+	git checkout foo/bar/baz &&
>       -+	test_when_finished "git clean -fdx" &&
>       ++test_expect_success 'rm -r with -C leaves submodule if cwd inside' '
>       ++	test_submodule_removal dir git -C .. rm -r my_submodule/
>       ++'
>        +
>       -+	mkdir untracked &&
>       -+	>untracked/random &&
>       -+	(
>       -+		cd untracked &&
>       -+		git stash --include-untracked &&
>       -+		git status
>       -+	) &&
>       ++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_path_is_missing untracked/random &&
>       -+	test_path_is_dir untracked
>       ++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
>    2:  f6129a8ac9c !  2:  200ddece05d setup: introduce startup_info->original_cwd
>       @@ cache.h: void overlay_tree_on_index(struct index_state *istate,
>        +	const char *original_cwd;
>         };
>         extern struct startup_info *startup_info;
>       ++extern const char *tmp_original_cwd;
>         
>       + /* merge.c */
>       + struct commit_list;
>        
>       - ## git.c ##
>       -@@ git.c: int cmd_main(int argc, const char **argv)
>       + ## common-main.c ##
>       +@@ common-main.c: static void restore_sigpipe_to_default(void)
>       + int main(int argc, const char **argv)
>       + {
>       + 	int result;
>       ++	struct strbuf tmp = STRBUF_INIT;
>       +
>       + 	trace2_initialize_clock();
>         
>       - 	trace_command_performance(argv);
>       +@@ common-main.c: int main(int argc, const char **argv)
>       + 	trace2_cmd_start(argv);
>       + 	trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
>         
>       -+	startup_info->original_cwd = xgetcwd();
>       ++	if (!strbuf_getcwd(&tmp))
>       ++		tmp_original_cwd = strbuf_detach(&tmp, NULL);
>        +
>       - 	/*
>       - 	 * "git-xxxx" is the same as "git xxxx", but we obviously:
>       - 	 *
>       + 	result = cmd_main(argc, argv);
>       +
>       + 	trace2_cmd_exit(result);
>        
>         ## setup.c ##
>       +@@ setup.c: static int work_tree_config_is_bogus;
>       +
>       + static struct startup_info the_startup_info;
>       + struct startup_info *startup_info = &the_startup_info;
>       ++const char *tmp_original_cwd;
>       +
>       + /*
>       +  * The input parameter must contain an absolute path, and it must already be
>        @@ setup.c: void setup_work_tree(void)
>         	initialized = 1;
>         }
>       @@ setup.c: void setup_work_tree(void)
>        +	const char *worktree = NULL;
>        +	int offset = -1;
>        +
>       -+	/*
>       -+	 * startup_info->original_cwd wass set early on in cmd_main(), unless
>       -+	 * we're an auxiliary tool like git-remote-http or test-tool.
>       -+	 */
>       -+	if (!startup_info->original_cwd)
>       ++	if (!tmp_original_cwd)
>        +		return;
>        +
>        +	/*
>        +	 * startup_info->original_cwd points to the current working
>        +	 * directory we inherited from our parent process, which is a
>       -+	 * directory we want to avoid incidentally removing.
>       ++	 * directory we want to avoid removing.
>        +	 *
>        +	 * For convience, we would like to have the path relative to the
>        +	 * worktree instead of an absolute path.
>       @@ setup.c: void setup_work_tree(void)
>        +	 */
>        +
>        +	/* Normalize the directory */
>       -+	strbuf_realpath(&tmp, startup_info->original_cwd, 1);
>       -+	free((char*)startup_info->original_cwd);
>       ++	strbuf_realpath(&tmp, tmp_original_cwd, 1);
>       ++	free((char*)tmp_original_cwd);
>       ++	tmp_original_cwd = NULL;
>        +	startup_info->original_cwd = strbuf_detach(&tmp, NULL);
>        +
>       -+	/* Find out if this is in the worktree */
>       ++	/*
>       ++	 * Get our worktree; we only protect the current working directory
>       ++	 * if it's in the worktree.
>       ++	 */
>        +	worktree = get_git_work_tree();
>       -+	if (worktree)
>       -+		offset = dir_inside_of(startup_info->original_cwd, worktree);
>       ++	if (!worktree)
>       ++		goto no_prevention_needed;
>       ++
>       ++	offset = dir_inside_of(startup_info->original_cwd, worktree);
>        +	if (offset >= 0) {
>        +		/*
>       ++		 * If startup_info->original_cwd == worktree, that is already
>       ++		 * protected and we don't need original_cwd as a secondary
>       ++		 * protection measure.
>       ++		 */
>       ++		if (!*(startup_info->original_cwd + offset))
>       ++			goto no_prevention_needed;
>       ++
>       ++		/*
>        +		 * original_cwd was inside worktree; precompose it just as
>        +		 * we do prefix so that built up paths will match
>        +		 */
>       @@ setup.c: void setup_work_tree(void)
>        +			precompose_string_if_needed(startup_info->original_cwd
>        +						    + offset);
>        +	}
>       ++	return;
>       ++
>       ++no_prevention_needed:
>       ++	free((char*)startup_info->original_cwd);
>       ++	startup_info->original_cwd = NULL;
>        +}
>        +
>         static int read_worktree_config(const char *var, const char *value, void *vdata)
>    3:  e74975e83cc !  3:  68ae90546fe unpack-trees: refuse to remove startup_info->original_cwd
>       @@ Commit message
>            Signed-off-by: Elijah Newren <newren@gmail.com>
>        
>         ## t/t2501-cwd-empty.sh ##
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'checkout does not clean cwd incidentally' '
>       - 	test_path_is_dir foo
>       +@@ t/t2501-cwd-empty.sh: test_expect_success 'checkout does not clean cwd incidentally' '
>         '
>         
>       --test_expect_failure 'checkout fails if cwd needs to be removed' '
>       -+test_expect_success 'checkout fails if cwd needs to be removed' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'checkout fails if cwd needs to be removed' '
>       +-	test_required_dir_removal failure git checkout fd_conflict
>       ++	test_required_dir_removal success git checkout fd_conflict
>       + '
>       +
>       + test_expect_success 'reset --hard does not clean cwd incidentally' '
>       +@@ t/t2501-cwd-empty.sh: test_expect_success 'merge fails if cwd needs to be removed; recursive friendly'
>       + 	(
>       + 		cd dirORfile &&
>       +
>       +-		# We would rather this failed, but we test for existing
>       +-		# rather than desired behavior
>       +-		git merge fd_conflict 2>../error
>       ++		test_must_fail git merge fd_conflict 2>../error
>       + 	) &&
>         
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'merge does not remove cwd incidentally' '
>       - 	test_path_is_dir subdir
>       +-	## Here is the behavior we would rather have:
>       +-	#test_path_is_dir dirORfile &&
>       +-	#grep "Refusing to remove the current working directory" error
>       +-	## But instead we test for existing behavior
>       +-	test_path_is_file dirORfile &&
>       +-	test_must_be_empty error
>       ++	test_path_is_dir dirORfile &&
>       ++	grep "Refusing to remove the current working directory" error
>         '
>         
>       --test_expect_failure 'merge fails if cwd needs to be removed' '
>       -+test_expect_success 'merge fails if cwd needs to be removed' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + GIT_TEST_MERGE_ALGORITHM=ort
>         
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'cherry-pick does not remove cwd incidentally' '
>       - 	test_path_is_dir subdir
>       + test_expect_success 'merge fails if cwd needs to be removed' '
>       +-	test_required_dir_removal failure git merge fd_conflict
>       ++	test_required_dir_removal success git merge fd_conflict
>         '
>         
>       --test_expect_failure 'cherry-pick fails if cwd needs to be removed' '
>       -+test_expect_success 'cherry-pick fails if cwd needs to be removed' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'cherry-pick does not clean cwd incidentally' '
>       +@@ t/t2501-cwd-empty.sh: test_expect_success 'cherry-pick does not clean cwd incidentally' '
>       + '
>         
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'rebase does not remove cwd incidentally' '
>       - 	test_path_is_dir subdir
>       + test_expect_success 'cherry-pick fails if cwd needs to be removed' '
>       +-	test_required_dir_removal failure git cherry-pick fd_conflict
>       ++	test_required_dir_removal success git cherry-pick fd_conflict
>         '
>         
>       --test_expect_failure 'rebase fails if cwd needs to be removed' '
>       -+test_expect_success 'rebase fails if cwd needs to be removed' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'rebase does not clean cwd incidentally' '
>       +@@ t/t2501-cwd-empty.sh: test_expect_success 'revert does not clean cwd incidentally' '
>       + '
>         
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'revert does not remove cwd incidentally' '
>       - 	test_path_is_dir subdir
>       + test_expect_success 'revert fails if cwd needs to be removed' '
>       +-	test_required_dir_removal failure git revert undo_fd_conflict
>       ++	test_required_dir_removal success git revert undo_fd_conflict
>         '
>         
>       --test_expect_failure 'revert fails if cwd needs to be removed' '
>       -+test_expect_success 'revert fails if cwd needs to be removed' '
>       - 	git checkout fd_conflict &&
>       - 	git revert HEAD &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'rm does not clean cwd incidentally' '
>        
>         ## unpack-trees.c ##
>        @@ unpack-trees.c: static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
>    4:  e06806e3a32 !  4:  1bb8905900c unpack-trees: add special cwd handling
>       @@ Commit message
>            Signed-off-by: Elijah Newren <newren@gmail.com>
>        
>         ## t/t2501-cwd-empty.sh ##
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'reset --hard does not clean cwd incidentally' '
>       - 	test_path_is_dir foo
>       +@@ t/t2501-cwd-empty.sh: test_expect_success 'reset --hard does not clean cwd incidentally' '
>         '
>         
>       --test_expect_failure 'reset --hard fails if cwd needs to be removed' '
>       -+test_expect_success 'reset --hard fails if cwd needs to be removed' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'reset --hard fails if cwd needs to be removed' '
>       +-	test_required_dir_removal failure git reset --hard fd_conflict
>       ++	test_required_dir_removal success git reset --hard fd_conflict
>       + '
>         
>       + test_expect_success 'merge does not clean cwd incidentally' '
>        
>         ## unpack-trees.c ##
>        @@ unpack-trees.c: static int verify_absent_1(const struct cache_entry *ce,
>    5:  46728f74ea1 !  5:  8a33d74e7cf symlinks: do not include startup_info->original_cwd in dir removal
>       @@ symlinks.c: void schedule_dir_for_removal(const char *name, int len)
>         				   &previous_slash);
>        
>         ## t/t2501-cwd-empty.sh ##
>       -@@ t/t2501-cwd-empty.sh: test_expect_success setup '
>       - 	git commit -m dirORfile
>       - '
>       +@@ t/t2501-cwd-empty.sh: test_required_dir_removal () {
>       + }
>         
>       --test_expect_failure 'checkout does not clean cwd incidentally' '
>       -+test_expect_success 'checkout does not clean cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_path_is_dir foo/bar &&
>       + test_expect_success 'checkout does not clean cwd incidentally' '
>       +-	test_incidental_dir_removal failure git checkout init
>       ++	test_incidental_dir_removal success git checkout init
>       + '
>         
>       + test_expect_success 'checkout fails if cwd needs to be removed' '
>        @@ t/t2501-cwd-empty.sh: test_expect_success 'checkout fails if cwd needs to be removed' '
>       - 	test_path_is_dir dirORfile
>         '
>         
>       --test_expect_failure 'reset --hard does not clean cwd incidentally' '
>       -+test_expect_success 'reset --hard does not clean cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_path_is_dir foo/bar &&
>       + test_expect_success 'reset --hard does not clean cwd incidentally' '
>       +-	test_incidental_dir_removal failure git reset --hard init
>       ++	test_incidental_dir_removal success git reset --hard init
>       + '
>         
>       + test_expect_success 'reset --hard fails if cwd needs to be removed' '
>        @@ t/t2501-cwd-empty.sh: test_expect_success 'reset --hard fails if cwd needs to be removed' '
>       - 	test_path_is_dir dirORfile
>         '
>         
>       --test_expect_failure 'merge does not remove cwd incidentally' '
>       -+test_expect_success 'merge does not remove cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'merge does not clean cwd incidentally' '
>       +-	test_incidental_dir_removal failure git merge reverted
>       ++	test_incidental_dir_removal success git merge reverted
>       + '
>         
>       + # This file uses some simple merges where
>        @@ t/t2501-cwd-empty.sh: test_expect_success 'merge fails if cwd needs to be removed' '
>       - 	test_path_is_dir dirORfile
>         '
>         
>       --test_expect_failure 'cherry-pick does not remove cwd incidentally' '
>       -+test_expect_success 'cherry-pick does not remove cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       -
>       -@@ t/t2501-cwd-empty.sh: test_expect_success 'cherry-pick fails if cwd needs to be removed' '
>       - 	test_path_is_dir dirORfile
>       + test_expect_success 'cherry-pick does not clean cwd incidentally' '
>       +-	test_incidental_dir_removal failure git cherry-pick reverted
>       ++	test_incidental_dir_removal success git cherry-pick reverted
>         '
>         
>       --test_expect_failure 'rebase does not remove cwd incidentally' '
>       -+test_expect_success 'rebase does not remove cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       -
>       + test_expect_success 'cherry-pick fails if cwd needs to be removed' '
>        @@ t/t2501-cwd-empty.sh: test_expect_success 'rebase fails if cwd needs to be removed' '
>       - 	test_path_is_dir dirORfile
>         '
>         
>       --test_expect_failure 'revert does not remove cwd incidentally' '
>       -+test_expect_success 'revert does not remove cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'revert does not clean cwd incidentally' '
>       +-	test_incidental_dir_removal failure git revert HEAD
>       ++	test_incidental_dir_removal success git revert HEAD
>       + '
>         
>       + test_expect_success 'revert fails if cwd needs to be removed' '
>    6:  01ce9444dae !  6:  11e4ec881bb clean: do not attempt to remove startup_info->original_cwd
>       @@ builtin/clean.c: static int remove_dirs(struct strbuf *path, const char *prefix,
>        +		strbuf_realpath(&realpath, path->buf, 1);
>        +
>        +		/*
>       -+		 * path and realpath are absolute; for comparison, we want
>       -+		 * startup_info->original_cwd to be an absolute path too.  We
>       -+		 * can use strbuf_realpath for this.  Also, if original_cwd
>       -+		 * started out as the empty string, then it corresponded to
>       -+		 * the top of the worktree, which is protected by other means
>       -+		 * so we just leave it blank.
>       ++		 * path and realpath are absolute; for comparison, we would
>       ++		 * like to transform startup_info->original_cwd to an absolute
>       ++		 * path too.
>        +		 */
>       -+		 if (*startup_info->original_cwd)
>       ++		 if (startup_info->original_cwd)
>        +			 strbuf_realpath(&real_ocwd,
>        +					 startup_info->original_cwd, 1);
>        +
>       @@ builtin/clean.c: static int remove_dirs(struct strbuf *path, const char *prefix,
>         	return ret;
>        
>         ## t/t2501-cwd-empty.sh ##
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'apply does not remove cwd incidentally' '
>       - 	test_path_is_dir subdir
>       - '
>       +@@ t/t2501-cwd-empty.sh: test_incidental_untracked_dir_removal () {
>       + }
>         
>       --test_expect_failure 'clean does not remove cwd incidentally' '
>       -+test_expect_success 'clean does not remove cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'clean does not remove cwd incidentally' '
>       +-	test_incidental_untracked_dir_removal failure \
>       +-		git -C .. clean -fd -e warnings . >warnings
>       ++	test_incidental_untracked_dir_removal success \
>       ++		git -C .. clean -fd -e warnings . >warnings &&
>       ++	grep "Refusing to remove current working directory" warnings
>       + '
>         
>       + test_expect_success 'stash does not remove cwd incidentally' '
>    -:  ----------- >  7:  39b1f3a225e rebase: do not attempt to remove startup_info->original_cwd
>    7:  edec0894ca2 !  8:  0110462a19c stash: do not attempt to remove startup_info->original_cwd
>       @@ Metadata
>         ## Commit message ##
>            stash: do not attempt to remove startup_info->original_cwd
>        
>       +    Since stash spawns a `clean` subprocess, make sure we run that from the
>       +    startup_info->original_cwd directory, so that the `clean` processs knows
>       +    to protect that directory.  Also, since the `clean` command might no
>       +    longer run from the toplevel, pass the ':/' magic pathspec to ensure we
>       +    still clean from the toplevel.
>       +
>            Signed-off-by: Elijah Newren <newren@gmail.com>
>        
>         ## builtin/stash.c ##
>       @@ builtin/stash.c: static int do_push_stash(const struct pathspec *ps, const char
>         
>         			cp.git_cmd = 1;
>        +			if (startup_info->original_cwd &&
>       -+			    *startup_info->original_cwd &&
>        +			    !is_absolute_path(startup_info->original_cwd))
>        +				cp.dir = startup_info->original_cwd;
>         			strvec_pushl(&cp.args, "clean", "--force",
>       @@ builtin/stash.c: static int do_push_stash(const struct pathspec *ps, const char
>        
>         ## t/t2501-cwd-empty.sh ##
>        @@ t/t2501-cwd-empty.sh: test_expect_success 'clean does not remove cwd incidentally' '
>       - 	test_path_is_dir untracked
>         '
>         
>       --test_expect_failure 'stash does not remove cwd incidentally' '
>       -+test_expect_success 'stash does not remove cwd incidentally' '
>       - 	git checkout foo/bar/baz &&
>       - 	test_when_finished "git clean -fdx" &&
>       + test_expect_success 'stash does not remove cwd incidentally' '
>       +-	test_incidental_untracked_dir_removal failure \
>       ++	test_incidental_untracked_dir_removal success \
>       + 		git stash --include-untracked
>       + '
>         
>    8:  1815f18592b !  9:  2c73a09a2e8 dir: avoid incidentally removing the original_cwd in remove_path()
>       @@ dir.h: int get_sparse_checkout_patterns(struct pattern_list *pl);
>        
>         ## t/t2501-cwd-empty.sh ##
>        @@ t/t2501-cwd-empty.sh: test_expect_success 'revert fails if cwd needs to be removed' '
>       - 	test_path_is_dir dirORfile
>         '
>         
>       --test_expect_failure 'rm does not remove cwd incidentally' '
>       -+test_expect_success 'rm does not remove cwd incidentally' '
>       - 	test_when_finished "git reset --hard" &&
>       - 	git checkout foo/bar/baz &&
>       + test_expect_success 'rm does not clean cwd incidentally' '
>       +-	test_incidental_dir_removal failure git rm bar/baz.t
>       ++	test_incidental_dir_removal success git rm bar/baz.t
>       + '
>         
>       -@@ t/t2501-cwd-empty.sh: test_expect_failure 'rm does not remove cwd incidentally' '
>       - 	test_path_is_dir foo
>       + test_expect_success 'apply does not remove cwd incidentally' '
>       + 	git diff HEAD HEAD~1 >patch &&
>       +-	test_incidental_dir_removal failure git apply ../patch
>       ++	test_incidental_dir_removal success git apply ../patch
>         '
>         
>       --test_expect_failure 'apply does not remove cwd incidentally' '
>       -+test_expect_success 'apply does not remove cwd incidentally' '
>       - 	test_when_finished "git reset --hard" &&
>       - 	git checkout foo/bar/baz &&
>       + test_incidental_untracked_dir_removal () {
>       +@@ t/t2501-cwd-empty.sh: test_expect_success '`rm -rf dir` even with only tracked files will remove somet
>       + 	) &&
>       +
>       + 	test_path_is_missing a/b/c/tracked &&
>       +-	## We would prefer if a/b was still present, though empty, since it
>       +-	## was the current working directory
>       +-	#test_path_is_dir a/b
>       +-	## But the current behavior is that it not only deletes the directory
>       +-	## a/b as requested, but also goes and deletes a
>       +-	test_path_is_missing a
>       ++	test_path_is_missing a/b/c &&
>       ++	test_path_is_dir a/b
>       + '
>         
>       + test_expect_success 'git version continues working from a deleted dir' '
>    9:  adaad7aeaac ! 10:  d4e50b4053d dir: new flag to remove_dir_recurse() to spare the original_cwd
>       @@ dir.h: int get_sparse_checkout_patterns(struct pattern_list *pl);
>          * of the above REMOVE_DIR_* constants. Return 0 on success.
>        
>         ## t/t2501-cwd-empty.sh ##
>       -@@ t/t2501-cwd-empty.sh: test_expect_success 'stash does not remove cwd incidentally' '
>       - 	test_path_is_dir untracked
>       - '
>       +@@ t/t2501-cwd-empty.sh: test_submodule_removal () {
>       + 	test_status=
>       + 	test $path_status = dir && test_status=test_must_fail
>       +
>       +-	# Actually, while path_status == dir && test_status=test_must_fail
>       +-	# reflect our desired behavior, current behavior is:
>       +-	path_status=missing
>       +-	test_status=
>       +-
>       + 	test_when_finished "git reset --hard HEAD~1" &&
>       + 	test_when_finished "rm -rf .git/modules/my_submodule" &&
>         
>       -+test_expect_success 'rm -r leaves submodule if cwd inside' '
>       -+	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_must_fail git --git-dir=../.git --work-tree=.. rm -r ../my_submodule/
>       -+	) &&
>       -+
>       -+	test_path_is_dir my_submodule
>       -+'
>       -+
>       -+test_expect_success 'rm -rf removes submodule even if cwd inside' '
>       -+	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 &&
>       -+		git --git-dir=../.git --work-tree=.. rm -rf ../my_submodule/
>       -+	) &&
>       -+
>       -+	test_path_is_missing my_submodule
>       -+'
>       -+
>       - test_done
>    -:  ----------- > 11:  7eb6281be4b t2501: simplify the tests since we can now assume desired behavior
> 


  parent reply	other threads:[~2021-11-30 11:04 UTC|newest]

Thread overview: 163+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-21  0:46 [PATCH 0/8] Avoid removing the current working directory, even if it becomes empty Elijah Newren via GitGitGadget
2021-11-21  0:46 ` [PATCH 1/8] t2501: add various tests for removing the current working directory Elijah Newren via GitGitGadget
2021-11-21 17:57   ` Ævar Arnfjörð Bjarmason
2021-11-23  1:45     ` Elijah Newren
2021-11-23  2:19       ` Ævar Arnfjörð Bjarmason
2021-11-23  3:11         ` Elijah Newren
2021-11-25 10:04           ` Ævar Arnfjörð Bjarmason
2021-11-21  0:46 ` [PATCH 2/8] repository, setup: introduce the_cwd Elijah Newren via GitGitGadget
2021-11-21  8:00   ` Junio C Hamano
2021-11-22 22:38     ` Elijah Newren
2021-11-21  8:56   ` René Scharfe
2021-11-22 23:09     ` Elijah Newren
2021-11-21  0:46 ` [PATCH 3/8] unpack-trees: refuse to remove the current working directory Elijah Newren via GitGitGadget
2021-11-21  0:46 ` [PATCH 4/8] unpack-trees: add special cwd handling Elijah Newren via GitGitGadget
2021-11-21  0:46 ` [PATCH 5/8] symlinks: do not include current working directory in dir removal Elijah Newren via GitGitGadget
2021-11-21  8:56   ` René Scharfe
2021-11-23  0:35     ` Elijah Newren
2021-11-21  0:46 ` [PATCH 6/8] clean: do not attempt to remove current working directory Elijah Newren via GitGitGadget
2021-11-21 17:51   ` Ævar Arnfjörð Bjarmason
2021-11-23  1:28     ` Elijah Newren
2021-11-21  0:46 ` [PATCH 7/8] stash: " Elijah Newren via GitGitGadget
2021-11-21  0:47 ` [PATCH 8/8] dir: avoid removing the " Elijah Newren via GitGitGadget
2021-11-23  0:39   ` Glen Choo
2021-11-23  1:19     ` Elijah Newren
2021-11-23 18:19       ` Glen Choo
2021-11-23 19:56         ` Elijah Newren
2021-11-23 20:32           ` Glen Choo
2021-11-23 21:57             ` Junio C Hamano
2021-11-23 23:23               ` Elijah Newren
2021-11-24  5:46                 ` Junio C Hamano
2021-11-23 23:13             ` Elijah Newren
2021-11-24  0:39               ` Glen Choo
2021-11-24  5:46                 ` Junio C Hamano
2021-11-24  1:10           ` Ævar Arnfjörð Bjarmason
2021-11-24  4:35             ` Elijah Newren
2021-11-24 11:14               ` Ævar Arnfjörð Bjarmason
2021-11-24 14:11                 ` Ævar Arnfjörð Bjarmason
2021-11-25  2:54                   ` Elijah Newren
2021-11-25 11:12                     ` Ævar Arnfjörð Bjarmason
2021-11-26 21:40                       ` The overhead of bin-wrappers/ (was: [PATCH 8/8] dir: avoid removing the current working directory) Ævar Arnfjörð Bjarmason
2021-11-24 14:33                 ` [PATCH 8/8] dir: avoid removing the current working directory Philip Oakley
2021-11-24 19:46                   ` Junio C Hamano
2021-11-25 12:54                     ` Philip Oakley
2021-11-25 13:51                       ` Ævar Arnfjörð Bjarmason
2021-11-25  2:48                 ` Elijah Newren
2021-11-24 19:43               ` Junio C Hamano
2021-11-21  8:11 ` [PATCH 0/8] Avoid removing the current working directory, even if it becomes empty Junio C Hamano
2021-11-25  8:39 ` [PATCH v2 0/9] " Elijah Newren via GitGitGadget
2021-11-25  8:39   ` [PATCH v2 1/9] t2501: add various tests for removing the current working directory Elijah Newren via GitGitGadget
2021-11-25 10:21     ` Ævar Arnfjörð Bjarmason
2021-11-25  8:39   ` [PATCH v2 2/9] setup: introduce startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-25 10:44     ` Ævar Arnfjörð Bjarmason
2021-11-26 17:55       ` Elijah Newren
2021-11-26  6:52     ` Junio C Hamano
2021-11-26 18:01       ` Elijah Newren
2021-11-29 14:05     ` Derrick Stolee
2021-11-29 17:18       ` Elijah Newren
2021-11-29 17:43         ` Derrick Stolee
2021-11-29 17:42       ` Junio C Hamano
2021-11-25  8:39   ` [PATCH v2 3/9] unpack-trees: refuse to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-25 10:56     ` Ævar Arnfjörð Bjarmason
2021-11-26 18:06       ` Elijah Newren
2021-11-29 14:10     ` Derrick Stolee
2021-11-29 17:26       ` Elijah Newren
2021-11-25  8:39   ` [PATCH v2 4/9] unpack-trees: add special cwd handling Elijah Newren via GitGitGadget
2021-11-29 14:14     ` Derrick Stolee
2021-11-29 17:33       ` Elijah Newren
2021-11-25  8:39   ` [PATCH v2 5/9] symlinks: do not include startup_info->original_cwd in dir removal Elijah Newren via GitGitGadget
2021-11-25  8:39   ` [PATCH v2 6/9] clean: do not attempt to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-25  8:39   ` [PATCH v2 7/9] stash: " Elijah Newren via GitGitGadget
2021-11-25 10:58     ` Ævar Arnfjörð Bjarmason
2021-11-26 18:04       ` Elijah Newren
2021-11-25  8:39   ` [PATCH v2 8/9] dir: avoid incidentally removing the original_cwd in remove_path() Elijah Newren via GitGitGadget
2021-11-25  8:39   ` [PATCH v2 9/9] dir: new flag to remove_dir_recurse() to spare the original_cwd Elijah Newren via GitGitGadget
2021-11-26 22:40   ` [PATCH v3 00/11] Avoid removing the current working directory, even if it becomes empty Elijah Newren via GitGitGadget
2021-11-26 22:40     ` [PATCH v3 01/11] t2501: add various tests for removing the current working directory Elijah Newren via GitGitGadget
2021-11-27 10:32       ` Ævar Arnfjörð Bjarmason
2021-11-27 19:16         ` Elijah Newren
2021-11-26 22:40     ` [PATCH v3 02/11] setup: introduce startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-27 10:35       ` Ævar Arnfjörð Bjarmason
2021-11-27 17:05         ` Elijah Newren
2021-11-27 10:40       ` Ævar Arnfjörð Bjarmason
2021-11-27 18:31         ` Elijah Newren
2021-11-28 18:04           ` Ævar Arnfjörð Bjarmason
2021-11-29 21:58             ` Elijah Newren
2021-11-26 22:40     ` [PATCH v3 03/11] unpack-trees: refuse to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-26 22:40     ` [PATCH v3 04/11] unpack-trees: add special cwd handling Elijah Newren via GitGitGadget
2021-11-26 22:40     ` [PATCH v3 05/11] symlinks: do not include startup_info->original_cwd in dir removal Elijah Newren via GitGitGadget
2021-11-26 22:40     ` [PATCH v3 06/11] clean: do not attempt to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-26 22:40     ` [PATCH v3 07/11] rebase: " Elijah Newren via GitGitGadget
2021-11-29 17:50       ` Derrick Stolee
2021-11-29 19:22         ` Elijah Newren
2021-11-29 19:42           ` Derrick Stolee
2021-11-26 22:40     ` [PATCH v3 08/11] stash: " Elijah Newren via GitGitGadget
2021-11-26 22:41     ` [PATCH v3 09/11] dir: avoid incidentally removing the original_cwd in remove_path() Elijah Newren via GitGitGadget
2021-11-26 22:41     ` [PATCH v3 10/11] dir: new flag to remove_dir_recurse() to spare the original_cwd Elijah Newren via GitGitGadget
2021-11-26 22:41     ` [PATCH v3 11/11] t2501: simplify the tests since we can now assume desired behavior Elijah Newren via GitGitGadget
2021-11-29 17:57     ` [PATCH v3 00/11] Avoid removing the current working directory, even if it becomes empty Derrick Stolee
2021-11-29 22:37     ` [PATCH v4 " Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 01/11] t2501: add various tests for removing the current working directory Elijah Newren via GitGitGadget
2021-11-30  6:47         ` Junio C Hamano
2021-11-30  6:53           ` Elijah Newren
2021-11-29 22:37       ` [PATCH v4 02/11] setup: introduce startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 03/11] unpack-trees: refuse to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 04/11] unpack-trees: add special cwd handling Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 05/11] symlinks: do not include startup_info->original_cwd in dir removal Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 06/11] clean: do not attempt to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 07/11] rebase: " Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 08/11] stash: " Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 09/11] dir: avoid incidentally removing the original_cwd in remove_path() Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 10/11] dir: new flag to remove_dir_recurse() to spare the original_cwd Elijah Newren via GitGitGadget
2021-11-29 22:37       ` [PATCH v4 11/11] t2501: simplify the tests since we can now assume desired behavior Elijah Newren via GitGitGadget
2021-11-29 23:38       ` [PATCH v4 00/11] Avoid removing the current working directory, even if it becomes empty Eric Sunshine
2021-11-30  0:16         ` Elijah Newren
2021-12-01  6:40       ` [PATCH v5 " Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 01/11] t2501: add various tests for removing the current working directory Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 02/11] setup: introduce startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 03/11] unpack-trees: refuse to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 04/11] unpack-trees: add special cwd handling Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 05/11] symlinks: do not include startup_info->original_cwd in dir removal Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 06/11] clean: do not attempt to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 07/11] rebase: " Elijah Newren via GitGitGadget
2022-01-25 20:26           ` [Bug] Rebase from worktree subdir is broken (was Re: [PATCH v5 07/11] rebase: do not attempt to remove startup_info->original_cwd) Glen Choo
2022-01-25 23:59             ` Elijah Newren
2022-01-26  0:30               ` Glen Choo
2022-01-26 19:04                 ` Elijah Newren
2022-01-26  0:32               ` Eric Sunshine
2022-01-26  0:38                 ` Eric Sunshine
2022-01-26  0:51                   ` Elijah Newren
2022-01-26  1:15                     ` Glen Choo
2022-01-26  1:38                       ` Elijah Newren
2022-01-26 11:00               ` Phillip Wood
2022-01-26 17:53                 ` Eric Sunshine
2022-01-27 11:01                   ` Phillip Wood
2022-01-27 20:03                   ` Elijah Newren
2022-02-05 11:23                     ` Eric Sunshine
2022-02-05 11:42                       ` Eric Sunshine
2022-02-05 22:35                         ` Elijah Newren
2021-12-01  6:40         ` [PATCH v5 08/11] stash: do not attempt to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 09/11] dir: avoid incidentally removing the original_cwd in remove_path() Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 10/11] dir: new flag to remove_dir_recurse() to spare the original_cwd Elijah Newren via GitGitGadget
2021-12-01  6:40         ` [PATCH v5 11/11] t2501: simplify the tests since we can now assume desired behavior Elijah Newren via GitGitGadget
2021-12-07 16:09         ` [PATCH v5 00/11] Avoid removing the current working directory, even if it becomes empty Derrick Stolee
2021-12-07 18:30           ` Ævar Arnfjörð Bjarmason
2021-12-07 20:57             ` Derrick Stolee
2021-12-08 10:23               ` Ævar Arnfjörð Bjarmason
2021-12-07 20:43           ` Elijah Newren
2021-12-07 21:00             ` Derrick Stolee
2021-12-09  5:08         ` [PATCH v6 " Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 01/11] t2501: add various tests for removing the current working directory Elijah Newren via GitGitGadget
2022-03-11 11:57             ` Ævar Arnfjörð Bjarmason
2021-12-09  5:08           ` [PATCH v6 02/11] setup: introduce startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 03/11] unpack-trees: refuse to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 04/11] unpack-trees: add special cwd handling Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 05/11] symlinks: do not include startup_info->original_cwd in dir removal Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 06/11] clean: do not attempt to remove startup_info->original_cwd Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 07/11] rebase: " Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 08/11] stash: " Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 09/11] dir: avoid incidentally removing the original_cwd in remove_path() Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 10/11] dir: new flag to remove_dir_recurse() to spare the original_cwd Elijah Newren via GitGitGadget
2021-12-09  5:08           ` [PATCH v6 11/11] t2501: simplify the tests since we can now assume desired behavior Elijah Newren via GitGitGadget
2021-11-30 11:04     ` Phillip Wood [this message]
2021-12-01  0:03       ` [PATCH v3 00/11] Avoid removing the current working directory, even if it becomes empty Elijah Newren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8e8b95d7-a4b4-6839-c572-8a43bbae8e0c@gmail.com \
    --to=phillip.wood123@gmail.com \
    --cc=avarab@gmail.com \
    --cc=chooglen@google.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=l.s.r@web.de \
    --cc=newren@gmail.com \
    --cc=peff@peff.net \
    --cc=philipoakley@iee.email \
    --cc=phillip.wood@dunelm.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).