]> git.ipfire.org Git - thirdparty/git.git/commitdiff
clean: do not attempt to remove startup_info->original_cwd
authorElijah Newren <newren@gmail.com>
Thu, 9 Dec 2021 05:08:30 +0000 (05:08 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 9 Dec 2021 21:33:13 +0000 (13:33 -0800)
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/clean.c
t/t2501-cwd-empty.sh

index 98a2860409bb4820af393ea9e50e58124fd7873e..3ff02bbbffeb7ed041b8a9af7f0b6f6d26c88492 100644 (file)
@@ -36,6 +36,8 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 static const char *msg_warn_remove_failed = N_("failed to remove %s");
 static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
+static const char *msg_skip_cwd = N_("Refusing to remove current working directory\n");
+static const char *msg_would_skip_cwd = N_("Would refuse to remove current working directory\n");
 
 enum color_clean {
        CLEAN_COLOR_RESET = 0,
@@ -153,6 +155,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 {
        DIR *dir;
        struct strbuf quoted = STRBUF_INIT;
+       struct strbuf realpath = STRBUF_INIT;
+       struct strbuf real_ocwd = STRBUF_INIT;
        struct dirent *e;
        int res = 0, ret = 0, gone = 1, original_len = path->len, len;
        struct string_list dels = STRING_LIST_INIT_DUP;
@@ -231,16 +235,36 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
        strbuf_setlen(path, original_len);
 
        if (*dir_gone) {
-               res = dry_run ? 0 : rmdir(path->buf);
-               if (!res)
-                       *dir_gone = 1;
-               else {
-                       int saved_errno = errno;
-                       quote_path(path->buf, prefix, &quoted, 0);
-                       errno = saved_errno;
-                       warning_errno(_(msg_warn_remove_failed), quoted.buf);
+               /*
+                * Normalize path components in path->buf, e.g. change '\' to
+                * '/' on Windows.
+                */
+               strbuf_realpath(&realpath, path->buf, 1);
+
+               /*
+                * 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)
+                        strbuf_realpath(&real_ocwd,
+                                        startup_info->original_cwd, 1);
+
+               if (!strbuf_cmp(&realpath, &real_ocwd)) {
+                       printf("%s", dry_run ? _(msg_would_skip_cwd) : _(msg_skip_cwd));
                        *dir_gone = 0;
-                       ret = 1;
+               } else {
+                       res = dry_run ? 0 : rmdir(path->buf);
+                       if (!res)
+                               *dir_gone = 1;
+                       else {
+                               int saved_errno = errno;
+                               quote_path(path->buf, prefix, &quoted, 0);
+                               errno = saved_errno;
+                               warning_errno(_(msg_warn_remove_failed), quoted.buf);
+                               *dir_gone = 0;
+                               ret = 1;
+                       }
                }
        }
 
@@ -250,6 +274,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
                        printf(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string);
        }
 out:
+       strbuf_release(&realpath);
+       strbuf_release(&real_ocwd);
        strbuf_release(&quoted);
        string_list_clear(&dels, 0);
        return ret;
index e4502d24d57f7726d5dc75fbb30f6e190c7fb41e..b1182390ba388dcac48afef716eab002bdc8188a 100755 (executable)
@@ -230,8 +230,9 @@ test_incidental_untracked_dir_removal () {
 }
 
 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' '