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 <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jiang Xin 2013-06-25 23:53:48 +08:00 коммит произвёл Junio C Hamano
Родитель 396049e5fb
Коммит 1769600208
2 изменённых файлов: 60 добавлений и 7 удалений

Просмотреть файл

@ -8,7 +8,7 @@ git-clean - Remove untracked files from the working tree
SYNOPSIS
--------
[verse]
'git clean' [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
'git clean' [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
DESCRIPTION
-----------
@ -34,7 +34,13 @@ OPTIONS
-f::
--force::
If the Git configuration variable clean.requireForce is not set
to false, 'git clean' will refuse to run unless given -f or -n.
to false, 'git clean' will refuse to run unless given -f, -n or
-i.
-i::
--interactive::
Show what would be done and the user must confirm before actually
cleaning.
-n::
--dry-run::

Просмотреть файл

@ -15,10 +15,11 @@
#include "quote.h"
static int force = -1; /* unset */
static int interactive;
static struct string_list del_list = STRING_LIST_INIT_DUP;
static const char *const builtin_clean_usage[] = {
N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
NULL
};
@ -143,6 +144,50 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
return ret;
}
static void interactive_main_loop(void)
{
struct strbuf confirm = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
struct string_list_item *item;
const char *qname;
while (del_list.nr) {
putchar('\n');
for_each_string_list_item(item, &del_list) {
qname = quote_path_relative(item->string, NULL, &buf);
printf(_(msg_would_remove), qname);
}
putchar('\n');
printf(_("Remove [y/n]? "));
if (strbuf_getline(&confirm, stdin, '\n') != EOF) {
strbuf_trim(&confirm);
} else {
/* Ctrl-D is the same as "quit" */
string_list_clear(&del_list, 0);
putchar('\n');
printf_ln("Bye.");
break;
}
if (confirm.len) {
if (!strncasecmp(confirm.buf, "yes", confirm.len)) {
break;
} else if (!strncasecmp(confirm.buf, "no", confirm.len) ||
!strncasecmp(confirm.buf, "quit", confirm.len)) {
string_list_clear(&del_list, 0);
printf_ln("Bye.");
break;
} else {
continue;
}
}
}
strbuf_release(&buf);
strbuf_release(&confirm);
}
int cmd_clean(int argc, const char **argv, const char *prefix)
{
int i, res;
@ -162,6 +207,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("do not print names of files removed")),
OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT__FORCE(&force, N_("force")),
OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
OPT_BOOLEAN('d', NULL, &remove_directories,
N_("remove whole directories")),
{ OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
@ -188,12 +234,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (ignored && ignored_only)
die(_("-x and -X cannot be used together"));
if (!dry_run && !force) {
if (!interactive && !dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -n nor -f given; "
die(_("clean.requireForce set to true and neither -i, -n nor -f given; "
"refusing to clean"));
else
die(_("clean.requireForce defaults to true and neither -n nor -f given; "
die(_("clean.requireForce defaults to true and neither -i, -n nor -f given; "
"refusing to clean"));
}
@ -267,7 +313,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
}
}
/* TODO: do interactive git-clean here, which will modify del_list */
if (interactive && del_list.nr > 0)
interactive_main_loop();
for_each_string_list_item(item, &del_list) {
struct stat st;