15
15
#include "quote.h"
16
16
17
17
static int force = -1 ; /* unset */
18
+ static int interactive ;
18
19
static struct string_list del_list = STRING_LIST_INIT_DUP ;
19
20
20
21
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>..." ),
22
23
NULL
23
24
};
24
25
@@ -143,6 +144,50 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
143
144
return ret ;
144
145
}
145
146
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
+
146
191
int cmd_clean (int argc , const char * * argv , const char * prefix )
147
192
{
148
193
int i , res ;
@@ -162,6 +207,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
162
207
OPT__QUIET (& quiet , N_ ("do not print names of files removed" )),
163
208
OPT__DRY_RUN (& dry_run , N_ ("dry run" )),
164
209
OPT__FORCE (& force , N_ ("force" )),
210
+ OPT_BOOL ('i' , "interactive" , & interactive , N_ ("interactive cleaning" )),
165
211
OPT_BOOLEAN ('d' , NULL , & remove_directories ,
166
212
N_ ("remove whole directories" )),
167
213
{ OPTION_CALLBACK , 'e' , "exclude" , & exclude_list , N_ ("pattern" ),
@@ -188,12 +234,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
188
234
if (ignored && ignored_only )
189
235
die (_ ("-x and -X cannot be used together" ));
190
236
191
- if (!dry_run && !force ) {
237
+ if (!interactive && ! dry_run && !force ) {
192
238
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; "
194
240
"refusing to clean" ));
195
241
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; "
197
243
"refusing to clean" ));
198
244
}
199
245
@@ -267,7 +313,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
267
313
}
268
314
}
269
315
270
- /* TODO: do interactive git-clean here, which will modify del_list */
316
+ if (interactive && del_list .nr > 0 )
317
+ interactive_main_loop ();
271
318
272
319
for_each_string_list_item (item , & del_list ) {
273
320
struct stat st ;
0 commit comments