Skip to content

Commit 1769600

Browse files
jiangxingitster
authored andcommitted
git-clean: add support for -i/--interactive
Show what would be done and the user must confirm before actually cleaning. Would remove ... Would remove ... Would remove ... Remove [y/n]? Press "y" to start cleaning, and press "n" if you want to abort. Signed-off-by: Jiang Xin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 396049e commit 1769600

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

Documentation/git-clean.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-clean - Remove untracked files from the working tree
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git clean' [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
11+
'git clean' [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
1212

1313
DESCRIPTION
1414
-----------
@@ -34,7 +34,13 @@ OPTIONS
3434
-f::
3535
--force::
3636
If the Git configuration variable clean.requireForce is not set
37-
to false, 'git clean' will refuse to run unless given -f or -n.
37+
to false, 'git clean' will refuse to run unless given -f, -n or
38+
-i.
39+
40+
-i::
41+
--interactive::
42+
Show what would be done and the user must confirm before actually
43+
cleaning.
3844

3945
-n::
4046
--dry-run::

builtin/clean.c

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
#include "quote.h"
1616

1717
static int force = -1; /* unset */
18+
static int interactive;
1819
static struct string_list del_list = STRING_LIST_INIT_DUP;
1920

2021
static const char *const builtin_clean_usage[] = {
21-
N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
22+
N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
2223
NULL
2324
};
2425

@@ -143,6 +144,50 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
143144
return ret;
144145
}
145146

147+
static void interactive_main_loop(void)
148+
{
149+
struct strbuf confirm = STRBUF_INIT;
150+
struct strbuf buf = STRBUF_INIT;
151+
struct string_list_item *item;
152+
const char *qname;
153+
154+
while (del_list.nr) {
155+
putchar('\n');
156+
for_each_string_list_item(item, &del_list) {
157+
qname = quote_path_relative(item->string, NULL, &buf);
158+
printf(_(msg_would_remove), qname);
159+
}
160+
putchar('\n');
161+
162+
printf(_("Remove [y/n]? "));
163+
if (strbuf_getline(&confirm, stdin, '\n') != EOF) {
164+
strbuf_trim(&confirm);
165+
} else {
166+
/* Ctrl-D is the same as "quit" */
167+
string_list_clear(&del_list, 0);
168+
putchar('\n');
169+
printf_ln("Bye.");
170+
break;
171+
}
172+
173+
if (confirm.len) {
174+
if (!strncasecmp(confirm.buf, "yes", confirm.len)) {
175+
break;
176+
} else if (!strncasecmp(confirm.buf, "no", confirm.len) ||
177+
!strncasecmp(confirm.buf, "quit", confirm.len)) {
178+
string_list_clear(&del_list, 0);
179+
printf_ln("Bye.");
180+
break;
181+
} else {
182+
continue;
183+
}
184+
}
185+
}
186+
187+
strbuf_release(&buf);
188+
strbuf_release(&confirm);
189+
}
190+
146191
int cmd_clean(int argc, const char **argv, const char *prefix)
147192
{
148193
int i, res;
@@ -162,6 +207,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
162207
OPT__QUIET(&quiet, N_("do not print names of files removed")),
163208
OPT__DRY_RUN(&dry_run, N_("dry run")),
164209
OPT__FORCE(&force, N_("force")),
210+
OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
165211
OPT_BOOLEAN('d', NULL, &remove_directories,
166212
N_("remove whole directories")),
167213
{ OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
@@ -188,12 +234,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
188234
if (ignored && ignored_only)
189235
die(_("-x and -X cannot be used together"));
190236

191-
if (!dry_run && !force) {
237+
if (!interactive && !dry_run && !force) {
192238
if (config_set)
193-
die(_("clean.requireForce set to true and neither -n nor -f given; "
239+
die(_("clean.requireForce set to true and neither -i, -n nor -f given; "
194240
"refusing to clean"));
195241
else
196-
die(_("clean.requireForce defaults to true and neither -n nor -f given; "
242+
die(_("clean.requireForce defaults to true and neither -i, -n nor -f given; "
197243
"refusing to clean"));
198244
}
199245

@@ -267,7 +313,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
267313
}
268314
}
269315

270-
/* TODO: do interactive git-clean here, which will modify del_list */
316+
if (interactive && del_list.nr > 0)
317+
interactive_main_loop();
271318

272319
for_each_string_list_item(item, &del_list) {
273320
struct stat st;

0 commit comments

Comments
 (0)