git-clean: refactor git-clean into two phases
Before introducing interactive git-clean, refactor git-clean operations into two phases: * hold cleaning items in del_list, * and remove them in a separate loop at the end. We will introduce interactive git-clean between the two phases. The interactive git-clean will show what would be done and must confirm before do real cleaning. Signed-off-by: Jiang Xin <worldhello.net@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jiang Xin committed
Jun 25, 2013 at 23:53 UTC
396049e5fb62ea921379d02133e1ff00cc47bb3f
1 file changed
+45
-19
builtin/clean.c
+45
-19
@@ -15,6 +15,7 @@
15
#include "quote.h"
16
17
static int force = -1; /* unset */
18
+static struct string_list del_list = STRING_LIST_INIT_DUP;
19
20
static const char *const builtin_clean_usage[] = {
21
N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
@@ -148,12 +149,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
149
int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
150
int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
151
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
151
- struct strbuf directory = STRBUF_INIT;
152
+ struct strbuf abs_path = STRBUF_INIT;
153
struct dir_struct dir;
154
static const char **pathspec;
155
struct strbuf buf = STRBUF_INIT;
156
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
157
struct exclude_list *el;
158
+ struct string_list_item *item;
159
const char *qname;
160
char *seen = NULL;
161
struct option options[] = {
@@ -223,6 +225,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
225
int matches = 0;
226
struct cache_entry *ce;
227
struct stat st;
228
+ const char *rel;
229
230
/*
231
* Remove the '/' at the end that directory
@@ -242,13 +245,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
245
continue; /* Yup, this one exists unmerged */
246
}
247
245
- /*
246
- * we might have removed this as part of earlier
247
- * recursive directory removal, so lstat() here could
248
- * fail with ENOENT.
249
- */
248
if (lstat(ent->name, &st))
251
- continue;
249
+ die_errno("Cannot lstat '%s'", ent->name);
250
251
if (pathspec) {
252
memset(seen, 0, argc > 0 ? argc : 1);
@@ -257,33 +255,61 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
255
}
256
257
if (S_ISDIR(st.st_mode)) {
260
- strbuf_addstr(&directory, ent->name);
258
if (remove_directories || (matches == MATCHED_EXACTLY)) {
262
- if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
263
- errors++;
264
- if (gone && !quiet) {
265
- qname = quote_path_relative(directory.buf, prefix, &buf);
266
- printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
267
- }
259
+ rel = relative_path(ent->name, prefix, &buf);
260
+ string_list_append(&del_list, rel);
261
}
269
- strbuf_reset(&directory);
262
} else {
263
if (pathspec && !matches)
264
continue;
273
- res = dry_run ? 0 : unlink(ent->name);
265
+ rel = relative_path(ent->name, prefix, &buf);
266
+ string_list_append(&del_list, rel);
267
+ }
268
+ }
269
+
270
+ /* TODO: do interactive git-clean here, which will modify del_list */
271
+
272
+ for_each_string_list_item(item, &del_list) {
273
+ struct stat st;
274
+
275
+ if (prefix)
276
+ strbuf_addstr(&abs_path, prefix);
277
+
278
+ strbuf_addstr(&abs_path, item->string);
279
+
280
+ /*
281
+ * we might have removed this as part of earlier
282
+ * recursive directory removal, so lstat() here could
283
+ * fail with ENOENT.
284
+ */
285
+ if (lstat(abs_path.buf, &st))
286
+ continue;
287
+
288
+ if (S_ISDIR(st.st_mode)) {
289
+ if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone))
290
+ errors++;
291
+ if (gone && !quiet) {
292
+ qname = quote_path_relative(item->string, NULL, &buf);
293
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
294
+ }
295
+ } else {
296
+ res = dry_run ? 0 : unlink(abs_path.buf);
297
if (res) {
275
- qname = quote_path_relative(ent->name, prefix, &buf);
298
+ qname = quote_path_relative(item->string, NULL, &buf);
299
warning(_(msg_warn_remove_failed), qname);
300
errors++;
301
} else if (!quiet) {
279
- qname = quote_path_relative(ent->name, prefix, &buf);
302
+ qname = quote_path_relative(item->string, NULL, &buf);
303
printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
304
}
305
}
306
+ strbuf_reset(&abs_path);
307
}
308
free(seen);
309
286
- strbuf_release(&directory);
310
+ strbuf_release(&abs_path);
311
+ strbuf_release(&buf);
312
+ string_list_clear(&del_list, 0);
313
string_list_clear(&exclude_list, 0);
314
return (errors != 0);
315
}