Skip to content

Commit c65744e

Browse files
newrengitster
authored andcommitted
clean: do not attempt to remove startup_info->original_cwd
Acked-by: Derrick Stolee <[email protected]> Acked-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 00fcce2 commit c65744e

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

builtin/clean.c

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
3636
static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
3737
static const char *msg_warn_remove_failed = N_("failed to remove %s");
3838
static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
39+
static const char *msg_skip_cwd = N_("Refusing to remove current working directory\n");
40+
static const char *msg_would_skip_cwd = N_("Would refuse to remove current working directory\n");
3941

4042
enum color_clean {
4143
CLEAN_COLOR_RESET = 0,
@@ -153,6 +155,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
153155
{
154156
DIR *dir;
155157
struct strbuf quoted = STRBUF_INIT;
158+
struct strbuf realpath = STRBUF_INIT;
159+
struct strbuf real_ocwd = STRBUF_INIT;
156160
struct dirent *e;
157161
int res = 0, ret = 0, gone = 1, original_len = path->len, len;
158162
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,
231235
strbuf_setlen(path, original_len);
232236

233237
if (*dir_gone) {
234-
res = dry_run ? 0 : rmdir(path->buf);
235-
if (!res)
236-
*dir_gone = 1;
237-
else {
238-
int saved_errno = errno;
239-
quote_path(path->buf, prefix, &quoted, 0);
240-
errno = saved_errno;
241-
warning_errno(_(msg_warn_remove_failed), quoted.buf);
238+
/*
239+
* Normalize path components in path->buf, e.g. change '\' to
240+
* '/' on Windows.
241+
*/
242+
strbuf_realpath(&realpath, path->buf, 1);
243+
244+
/*
245+
* path and realpath are absolute; for comparison, we would
246+
* like to transform startup_info->original_cwd to an absolute
247+
* path too.
248+
*/
249+
if (startup_info->original_cwd)
250+
strbuf_realpath(&real_ocwd,
251+
startup_info->original_cwd, 1);
252+
253+
if (!strbuf_cmp(&realpath, &real_ocwd)) {
254+
printf("%s", dry_run ? _(msg_would_skip_cwd) : _(msg_skip_cwd));
242255
*dir_gone = 0;
243-
ret = 1;
256+
} else {
257+
res = dry_run ? 0 : rmdir(path->buf);
258+
if (!res)
259+
*dir_gone = 1;
260+
else {
261+
int saved_errno = errno;
262+
quote_path(path->buf, prefix, &quoted, 0);
263+
errno = saved_errno;
264+
warning_errno(_(msg_warn_remove_failed), quoted.buf);
265+
*dir_gone = 0;
266+
ret = 1;
267+
}
244268
}
245269
}
246270

@@ -250,6 +274,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
250274
printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
251275
}
252276
out:
277+
strbuf_release(&realpath);
278+
strbuf_release(&real_ocwd);
253279
strbuf_release(&quoted);
254280
string_list_clear(&dels, 0);
255281
return ret;

t/t2501-cwd-empty.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,9 @@ test_incidental_untracked_dir_removal () {
230230
}
231231

232232
test_expect_success 'clean does not remove cwd incidentally' '
233-
test_incidental_untracked_dir_removal failure \
234-
git -C .. clean -fd -e warnings . >warnings
233+
test_incidental_untracked_dir_removal success \
234+
git -C .. clean -fd -e warnings . >warnings &&
235+
grep "Refusing to remove current working directory" warnings
235236
'
236237

237238
test_expect_success 'stash does not remove cwd incidentally' '

0 commit comments

Comments
 (0)