git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] clean: confirm before cleaning files and directories

From
Jiang Xin <worldhello.net@gmail.com>
Date
Apr 26, 2013, 08:07 UTC
Message-ID
<1826d070612808b301f9295838e226e02d8097ad.1366963586.git.worldhello.net@gmail.com>

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@gmail.com>
---
 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
Next: Matthieu Moy
Message 1 of 30 in “clean: confirm before cleaning files and directories”
  1. clean: confirm before cleaning files and directoriesJiang Xin, Apr 26, 2013
  2. Matthieu MoyApr 26, 2013
  3. Jiang XinApr 26, 2013
  4. Matthieu MoyApr 26, 2013
  5. Jiang XinApr 26, 2013
  6. Thomas RastApr 26, 2013
  7. Junio C HamanoApr 26, 2013
  8. Matthieu MoyApr 26, 2013
  9. Junio C HamanoApr 26, 2013
  10. Junio C HamanoApr 26, 2013
  11. Jiang XinApr 27, 2013
  12. Add support for -i/--interactive to git-cleanJiang Xin, Apr 27, 2013
  13. Matthieu MoyApr 27, 2013
  14. Junio C HamanoApr 27, 2013
  15. Eric SunshineApr 28, 2013
  16. Matthieu MoyApr 29, 2013
  17. clean: Introduce -z for machine readable outputMichael J Gruber, Apr 29, 2013
  18. Matthieu MoyApr 29, 2013
  19. Jiang XinApr 29, 2013
  20. Add support for -i/--interactive to git-cleanJiang Xin, Apr 30, 2013
  21. Matthieu MoyMay 1, 2013
  22. 1/3 Add support for -i/--interactive to git-cleanJiang Xin, May 2, 2013
  23. 2/3 Show items of interactive git-clean in columnsJiang Xin, May 2, 2013
  24. 3/3 Add colors to interactive git-cleanJiang Xin, May 2, 2013
  25. Matthieu MoyMay 2, 2013
  26. Jiang XinMay 3, 2013
  27. Matthieu MoyMay 2, 2013
  28. Jiang XinMay 3, 2013
  29. Matthieu MoyMay 3, 2013
  30. Jiang XinMay 2, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.