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

[PATCH] clean: Introduce -z for machine readable output

From
Michael J Gruber <git@drmicha.warpmail.net>
Date
Apr 29, 2013, 14:30 UTC
Message-ID
<6733a9080da07ace27c3252de2399be339b4e349.1367245712.git.git@drmicha.warpmail.net>
In-Reply-To
<vpqwqrl931e.fsf@grenoble-inp.fr>

-z makes clean output only the names of paths which are or would be deleted, and separates them with \0.

Use as "xargs -0 -a <(git clean -nz [-d]) rm -ri", e.g., as a quick "git clean -i".

Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>
---
Here's an alternative approach to that problem with a complete different attach
vector but a similar purpose. I've been using it for a while, but it's kind of
unpolished. My "git-clean-i" looks like:

--->%--- #!/bin/bash xargs -0 -a <(git clean -n -z "$@") rm -ri --->%---

 Documentation/git-clean.txt |  9 ++++++++-
 builtin/clean.c             | 27 +++++++++++++++++++--------
 2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index bdc3ab8..849e775 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -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] [-n] [-q] [-z] [-e <pattern>] [-x | -X] [--] <path>...
 
 DESCRIPTION
 -----------
@@ -63,6 +63,13 @@ OPTIONS
 	Remove only files ignored by Git.  This may be useful to rebuild
 	everything from scratch, but keep manually created files.
 
+-z::
+	Use machine readable output for (to be) removed paths: Output the paths
+	which are or would be removed only (without extra wording) and
+	separate them with \0.
++
+This does not imply `-n` but can be combined with it.
+
 SEE ALSO
 --------
 linkgit:gitignore[5]
diff --git a/builtin/clean.c b/builtin/clean.c
index 04e396b..0ebba24 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -41,8 +41,18 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
+void write_name(const char *fmt, const char *name, int nul_terminated)
+{
+	if (nul_terminated) {
+		fputs(name, stdout);
+		fputc(0, stdout);
+	} else {
+		printf(fmt, name);
+	}
+}
+
 static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
-		int dry_run, int quiet, int *dir_gone)
+		int dry_run, int quiet, int *dir_gone, int nul_terminated)
 {
 	DIR *dir;
 	struct strbuf quoted = STRBUF_INIT;
@@ -57,8 +67,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 			!resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
 		if (!quiet) {
 			quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
-			printf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
-					quoted.buf);
+			write_name(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
+					quoted.buf, nul_terminated);
 		}
 
 		*dir_gone = 0;
@@ -91,7 +101,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 		if (lstat(path->buf, &st))
 			; /* fall thru */
 		else if (S_ISDIR(st.st_mode)) {
-			if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
+			if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone, nul_terminated))
 				ret = 1;
 			if (gone) {
 				quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
@@ -136,7 +146,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 
 	if (!*dir_gone && !quiet) {
 		for (i = 0; i < dels.nr; i++)
-			printf(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string);
+			write_name(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string, nul_terminated);
 	}
 	string_list_clear(&dels, 0);
 	return ret;
@@ -146,7 +156,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 {
 	int i, res;
 	int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
-	int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
+	int ignored_only = 0, config_set = 0, errors = 0, gone = 1, nul_terminated = 0;
 	int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
 	struct strbuf directory = STRBUF_INIT;
 	struct dir_struct dir;
@@ -167,6 +177,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")),
 		OPT_BOOLEAN('X', NULL, &ignored_only,
 				N_("remove only ignored files")),
+		OPT_BOOLEAN('z', NULL, &nul_terminated, "(actually or to be) removed paths are separated with NUL character"),
 		OPT_END()
 	};
 
@@ -259,7 +270,7 @@ 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)) {
-				if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
+				if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone, nul_terminated))
 					errors++;
 				if (gone && !quiet) {
 					qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
@@ -277,7 +288,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 				errors++;
 			} else if (!quiet) {
 				qname = quote_path_relative(ent->name, -1, &buf, prefix);
-				printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
+				write_name(dry_run ? _(msg_would_remove) : _(msg_remove), qname, nul_terminated);
 			}
 		}
 	}
-- 
1.8.3.rc0.297.g8c90ec5
Previous: Matthieu MoyNext: Matthieu Moy
Message 17 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.