]> git.ipfire.org Git - thirdparty/git.git/commitdiff
dir: new flag to remove_dir_recurse() to spare the original_cwd
authorElijah Newren <newren@gmail.com>
Thu, 9 Dec 2021 05:08:34 +0000 (05:08 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 9 Dec 2021 21:33:13 +0000 (13:33 -0800)
remove_dir_recurse(), and its non-static wrapper called
remove_dir_recursively(), both take flags for modifying its behavior.
As with the previous commits, we would generally like to protect
the original_cwd, but we want to forced user commands (e.g. 'git rm -rf
...') or other special cases to remove it.  Add a flag for this purpose.
After reading through every caller of remove_dir_recursively() in the
current codebase, there was only one that should be adjusted and that
one only in a very unusual circumstance.  Add a pair of new testcases to
highlight that very specific case involving submodules && --git-dir &&
--work-tree.

Acked-by: Derrick Stolee <stolee@gmail.com>
Acked-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/rm.c
dir.c
dir.h
t/t2501-cwd-empty.sh

index 3d0967cdc11308b966e6225d6b95dd7ae90ab364..b4132e5d8eebe5d486c9b76690f426c16ab53f58 100644 (file)
@@ -399,12 +399,13 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        if (!index_only) {
                int removed = 0, gitmodules_modified = 0;
                struct strbuf buf = STRBUF_INIT;
+               int flag = force ? REMOVE_DIR_PURGE_ORIGINAL_CWD : 0;
                for (i = 0; i < list.nr; i++) {
                        const char *path = list.entry[i].name;
                        if (list.entry[i].is_submodule) {
                                strbuf_reset(&buf);
                                strbuf_addstr(&buf, path);
-                               if (remove_dir_recursively(&buf, 0))
+                               if (remove_dir_recursively(&buf, flag))
                                        die(_("could not remove '%s'"), path);
 
                                removed = 1;
diff --git a/dir.c b/dir.c
index 97d6b71c87255d5bcf37e4b0553f3e8ea8b6edda..52064345a6b759e2fd9d3fa6bb5a57ce3ed2fcf5 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -3204,6 +3204,7 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
        int ret = 0, original_len = path->len, len, kept_down = 0;
        int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
        int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL);
+       int purge_original_cwd = (flag & REMOVE_DIR_PURGE_ORIGINAL_CWD);
        struct object_id submodule_head;
 
        if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
@@ -3259,9 +3260,14 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
        closedir(dir);
 
        strbuf_setlen(path, original_len);
-       if (!ret && !keep_toplevel && !kept_down)
-               ret = (!rmdir(path->buf) || errno == ENOENT) ? 0 : -1;
-       else if (kept_up)
+       if (!ret && !keep_toplevel && !kept_down) {
+               if (!purge_original_cwd &&
+                   startup_info->original_cwd &&
+                   !strcmp(startup_info->original_cwd, path->buf))
+                       ret = -1; /* Do not remove current working directory */
+               else
+                       ret = (!rmdir(path->buf) || errno == ENOENT) ? 0 : -1;
+       } else if (kept_up)
                /*
                 * report the uplevel that it is not an error that we
                 * did not rmdir() our directory.
diff --git a/dir.h b/dir.h
index d6a5d03bec2e4dd21cf4788e9682b0e03fa4ef84..8e02dfb505d163eca3c33d17e495be8f166b83e5 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -495,6 +495,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl);
 /* Remove the contents of path, but leave path itself. */
 #define REMOVE_DIR_KEEP_TOPLEVEL 04
 
+/* Remove the_original_cwd too */
+#define REMOVE_DIR_PURGE_ORIGINAL_CWD 0x08
+
 /*
  * Remove path and its contents, recursively. flags is a combination
  * of the above REMOVE_DIR_* constants. Return 0 on success.
index ce2efb9d30a8b0bb4e29ea13cd53974debbdbc77..bc92230f2f2c32d490ca94da61ffb202375c5e68 100755 (executable)
@@ -291,11 +291,6 @@ 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" &&