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
>
next prev 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).