When running `git clean`, it will be convenient and safe to show a confirm dialog and only delete files and directories when confirmed. The confirm dialog will popup when: * run `git clean` in interactive sessions, * not a dry run, * and not quiet. There may be existing scripts that call `git clean -f` while leave the standard input and the standard output of the `git clean` connected to whatever environment the scripts were started, and such invocation might trigger the confirm dialog. In this case, add a `-q` option, such as `git clean -q -f`, then the confirm dialog won't popup. Signed-off-by: Jiang Xin <worldhello.net@xxxxxxxxx> --- builtin/clean.c | 66 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/builtin/clean.c b/builtin/clean.c index 04e39..e31a1 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -169,6 +169,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix) N_("remove only ignored files")), OPT_END() }; + struct string_list dels = STRING_LIST_INIT_DUP; + struct string_list_item *item; + struct strbuf confirm = STRBUF_INIT; + int confirmed = 0; git_config(git_clean_config, NULL); if (force < 0) @@ -257,33 +261,67 @@ int cmd_clean(int argc, const char **argv, const char *prefix) } if (S_ISDIR(st.st_mode)) { - strbuf_addstr(&directory, ent->name); if (remove_directories || (matches == MATCHED_EXACTLY)) { + string_list_append(&dels, ent->name); + } + } else { + if (pathspec && !matches) + continue; + string_list_append(&dels, ent->name); + } + } + + if (!isatty(0) || !isatty(1) || quiet || dry_run) { + confirmed = 1; + } + + if (!confirmed && dels.nr > 0) { + for_each_string_list_item(item, &dels) { + qname = quote_path_relative(item->string, -1, &buf, prefix); + printf(_(msg_would_remove), qname); + } + printf(_("Are you sure [y/N]? ")); + strbuf_getline(&confirm, stdin, '\n'); + strbuf_trim(&confirm); + if (!strcasecmp(confirm.buf, "y")) { + confirmed = 1; + } + } + + if (confirmed) { + for_each_string_list_item(item, &dels) { + struct stat st; + + if (lstat(item->string, &st)) + continue; + + if (S_ISDIR(st.st_mode)) { + strbuf_addstr(&directory, item->string); if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone)) errors++; if (gone && !quiet) { qname = quote_path_relative(directory.buf, directory.len, &buf, prefix); printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname); } - } - strbuf_reset(&directory); - } else { - if (pathspec && !matches) - continue; - res = dry_run ? 0 : unlink(ent->name); - if (res) { - qname = quote_path_relative(ent->name, -1, &buf, prefix); - warning(_(msg_warn_remove_failed), qname); - errors++; - } else if (!quiet) { - qname = quote_path_relative(ent->name, -1, &buf, prefix); - printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname); + strbuf_reset(&directory); + } else { + res = dry_run ? 0 : unlink(item->string); + if (res) { + qname = quote_path_relative(item->string, -1, &buf, prefix); + warning(_(msg_warn_remove_failed), qname); + errors++; + } else if (!quiet) { + qname = quote_path_relative(item->string, -1, &buf, prefix); + printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname); + } } } } free(seen); strbuf_release(&directory); + strbuf_release(&confirm); string_list_clear(&exclude_list, 0); + string_list_clear(&dels, 0); return (errors != 0); } -- 1.8.2.1.628.gcd33b41 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html