{"thread":{"id":"13552","subject":"[PATCH] Add a -z option to 'git status' to safely feed shell programs with path names","startedAt":"2008-05-17T02:33:40Z","lastAt":"2008-05-17T11:02:51Z","messageCount":5,"participants":["Sebastien Gross","Shawn O. Pearce","Johannes Schindelin","Mike Hommey"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"77172","messageId":"20080517023340.GG10006@kali.thurne.chezwam.org","threadId":"13552","inReplyTo":null,"subject":"[PATCH] Add a -z option to 'git status' to safely feed shell programs with path names","fromName":"Sebastien Gross","fromEmail":"seb-git@chezwam.org","sentAt":"2008-05-17T02:33:40Z","receivedAt":"2008-05-17T02:33:40Z","isPatch":true,"sender":{"key":"seb-git@chezwam.org","avatar":null},"body":"Add a -z option to 'git status' to get a list of all files\nbut ignored, starting with modification type or 'untracked'\nas prefix and ending with '\\0'.\n\nBasically the output is similar to 'git status' but with no\ncomments and suitable to shell programs that should process\nfilenames (xargs would help for some of them) in a safe way.\n\nModifications:\n\n  * Documentation/git-commit.txt,Documentation/git-status.txt:\n    add description for -z option.\n  * builtin-commit.c: add support for '-z' and complains if\n    this option is given to `git-commit`.\n  * quote.*: add 'make_path_relative' function which acts like\n    the 'quote_path_relative' but do not quote path (only give\n    the relative path to the perfix).\n  * wt-status.*: add many tests and code to handle '-z'.\n---\n\n\nA file would match the template:\n\n ([status] [action]|untracked):file_name\n\nWhere:\n\n * `status` is: [ \"updated\", \"changed\" ]\n * `action` is: [ \"new file\", \"deleted\", \"modified\",\n \t\"changetype\", \"unknown\", \"unmerged\" ]\n\nBoth \"copied\" and \"renamed\" are no used.\n\nHope nothing would be broken. This patch was generated against\n1fbb58b4153e90eda08c2b022ee32d90729582e6.\n\nExamples:\n\n * Remove all untracked files:\n\n   git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^untracked/ \\\n\t{sub(\"^.+:\", \"\");print}' | xargs -0 -r rm\n\n * List all updated file regardless the modification:\n\n   git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^updated/ \\\n\t{sub(\"^.+:\", \"\");print}' | xargs -0 -n 1\n\n\n Documentation/git-commit.txt |   10 ++++-\n Documentation/git-status.txt |   29 ++++++++++++++\n builtin-commit.c             |    8 +++-\n quote.c                      |   42 ++++++++++++++++++++\n quote.h                      |    2 +\n wt-status.c                  |   87 +++++++++++++++++++++++++++++-------------\n wt-status.h                  |    1 +\n 7 files changed, 150 insertions(+), 29 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex c3c9f5b..2ffb95b 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -8,7 +8,7 @@ git-commit - Record changes to the repository\n SYNOPSIS\n --------\n [verse]\n-'git-commit' [-a | --interactive] [-s] [-v] [-u]\n+'git-commit' [-a | --interactive] [-s] [-v] [-u] [-z]\n \t   [(-c | -C) <commit> | -F <file> | -m <msg> | --amend]\n \t   [--allow-empty] [--no-verify] [-e] [--author <author>]\n \t   [--cleanup=<mode>] [--] [[-i | -o ]<file>...]\n@@ -166,6 +166,14 @@ but can be used to amend a merge commit.\n -q|--quiet::\n \tSuppress commit summary message.\n \n+-z::\n+\tOnly if calling linkgit:git-status[1]. Show all file\n+\tnames that are not ignored, prefixed by its modification\n+\ttype (or untracked) and suffixed by '\\0'. Useful for\n+\tprocessing file with unsafe names.\n+\tSee linkgit:git-status[1] for more information about tag\n+\tprefix.\n+\n \\--::\n \tDo not interpret any more arguments as options.\n \ndiff --git a/Documentation/git-status.txt b/Documentation/git-status.txt\nindex ea4376a..61deb25 100644\n--- a/Documentation/git-status.txt\n+++ b/Documentation/git-status.txt\n@@ -34,6 +34,21 @@ OUTPUT\n The output from this command is designed to be used as a commit\n template comment, and all the output lines are prefixed with '#'.\n \n+One exception is made with the `-z` option. In this case, all files\n+are printed prefixed with a modification tag, and suffixed with '\\0'.\n+In that case all files can be piped to any shell program.\n+The output format is the following:\n+\n+ ([status] [action]|untracked):file_name\n+\n+Where:\n+\n+  * `status` is: [ \"updated\", \"changed\" ]\n+  * `action` is: [ \"new file\", \"deleted\", \"modified\", \"changetype\",\n+    \"unknown\", \"unmerged\" ]\n+\n+Both \"copied\" and \"renamed\" are no used.\n+\n The paths mentioned in the output, unlike many other git commands, are\n made relative to the current directory if you are working in a\n subdirectory (this is on purpose, to help cutting and pasting). See\n@@ -57,6 +72,20 @@ to -1 or an unlimited number), the submodule summary will be enabled and a\n summary of commits for modified submodules will be shown (see --summary-limit\n option of linkgit:git-submodule[1]).\n \n+EXAMPLES\n+--------\n+\n+Remove all untracked files:\n+\n+   git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^untracked/ \\\n+  \t{sub(\"^.+:\", \"\");print}' | xargs -0 -r rm\n+\n+\n+List all updated file regardless the modification:\n+\n+  git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^updated/ \\\n+  \t{sub(\"^.+:\", \"\");print}' | xargs -0 -n 1\n+\n See Also\n --------\n linkgit:gitignore[5]\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex 0baec6d..2b37a85 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -50,6 +50,8 @@ static char *edit_message, *use_message;\n static char *author_name, *author_email, *author_date;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n static int quiet, verbose, untracked_files, no_verify, allow_empty;\n+static int ls_files_zeroed;\n+\n /*\n  * The default commit message cleanup mode will remove the lines\n  * beginning with # (shell comments) and leading and trailing\n@@ -106,6 +108,8 @@ static struct option builtin_commit_options[] = {\n \tOPT_BOOLEAN(0, \"allow-empty\", &allow_empty, \"ok to record an empty change\"),\n \tOPT_STRING(0, \"cleanup\", &cleanup_arg, \"default\", \"how to strip spaces and #comments from message\"),\n \n+\tOPT_GROUP(\"List files (only for status)\"),\n+\tOPT_BOOLEAN('z', 0, &ls_files_zeroed, \"\\\\0 line termination on output\"),\n \tOPT_END()\n };\n \n@@ -348,6 +352,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int\n \ts.index_file = index_file;\n \ts.fp = fp;\n \ts.nowarn = nowarn;\n+\ts.ls_files_zeroed = ls_files_zeroed;\n \n \twt_status_print(&s);\n \n@@ -899,7 +904,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \tgit_config(git_commit_config);\n \n \targc = parse_and_validate_options(argc, argv, builtin_commit_usage);\n-\n+\tif (ls_files_zeroed)\n+\t\tdie(\"option -z is nonsense with commit\");\n \tindex_file = prepare_index(argc, argv, prefix);\n \n \t/* Set up everything for writing the commit object.  This includes\ndiff --git a/quote.c b/quote.c\nindex d5cf9d8..6ab6c32 100644\n--- a/quote.c\n+++ b/quote.c\n@@ -303,6 +303,48 @@ char *quote_path_relative(const char *in, int len,\n }\n \n /*\n+ * return path as relative to the given prefix but do not quote it\n+ * Useful to build a zero-terminated string of the path.\n+ * TODO: Factorize this function with quote_path_relative\n+ */\n+char *make_path_relative(const char *in, int len,\n+\t\t\t  struct strbuf *out, const char *prefix)\n+{\n+\n+\tif (len < 0)\n+\t\tlen = strlen(in);\n+\n+\t/* \"../\" prefix itself does not need quoting, but \"in\" might. */\n+\tstrbuf_setlen(out, 0);\n+\tstrbuf_grow(out, len);\n+\t\n+\tif (prefix) {\n+\t\tint off = 0;\n+\t\twhile (prefix[off] && off < len && prefix[off] == in[off])\n+\t\t\tif (prefix[off] == '/') {\n+\t\t\t\tprefix += off + 1;\n+\t\t\t\tin += off + 1;\n+\t\t\t\tlen -= off + 1;\n+\t\t\t\toff = 0;\n+\t\t\t} else\n+\t\t\t\toff++;\n+\n+\t\tfor (; *prefix; prefix++)\n+\t\t\tif (*prefix == '/')\n+\t\t\t\tstrbuf_addstr(out, \"../\");\n+\t}\n+\n+\n+\tstrbuf_addstr(out, in);\n+\t/* quote_c_style_counted (in, len, out, NULL, 1); */\n+\n+\tif (!out->len)\n+\t\tstrbuf_addstr(out, \"./\");\n+\n+\treturn out->buf;\n+}\n+\n+/*\n  * C-style name unquoting.\n  *\n  * Quoted should point at the opening double quote.\ndiff --git a/quote.h b/quote.h\nindex c5eea6f..1934c60 100644\n--- a/quote.h\n+++ b/quote.h\n@@ -50,6 +50,8 @@ extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,\n /* quote path as relative to the given prefix */\n char *quote_path_relative(const char *in, int len,\n \t\t\t  struct strbuf *out, const char *prefix);\n+char *make_path_relative(const char *in, int len,\n+\t\t\t  struct strbuf *out, const char *prefix);\n \n /* quoting as a string literal for other languages */\n extern void perl_quote_print(FILE *stream, const char *src);\ndiff --git a/wt-status.c b/wt-status.c\nindex a44c543..1a007e1 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -93,42 +93,58 @@ static void wt_status_print_filepair(struct wt_status *s,\n \tconst char *c = color(t);\n \tconst char *one, *two;\n \tstruct strbuf onebuf, twobuf;\n+\tchar *updated_prefix=\"updated \", *changed_prefix=\"changed \", *pfx = 0;\n \n \tstrbuf_init(&onebuf, 0);\n \tstrbuf_init(&twobuf, 0);\n-\tone = quote_path(p->one->path, -1, &onebuf, s->prefix);\n-\ttwo = quote_path(p->two->path, -1, &twobuf, s->prefix);\n \n-\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\tif (!s->ls_files_zeroed) {\n+\t\tone = quote_path(p->one->path, -1, &onebuf, s->prefix);\n+\t\ttwo = quote_path(p->two->path, -1, &twobuf, s->prefix);\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\t} else {\n+\t\tone = make_path_relative(p->one->path, -1, &onebuf, s->prefix);\n+\t\ttwo = 0;\t/* Maybe in a future usage ? */\n+\t\tpfx = t != WT_STATUS_CHANGED ? changed_prefix : updated_prefix;\n+\t}\n \tswitch (p->status) {\n \tcase DIFF_STATUS_ADDED:\n+\t\ts->ls_files_zeroed ? printf(\"%snew file:%s%c\", pfx, one, 0) :\n \t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n+\t\tif (!s->ls_files_zeroed)\n+\t\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n+\t\ts->ls_files_zeroed ? printf(\"%sdeleted:%s%c\", pfx, one, 0) :\n \t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n+\t\ts->ls_files_zeroed ? printf(\"%smodified:%s%c\", pfx, one, 0) :\n \t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n+\t\tif (!s->ls_files_zeroed)\n+\t\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n+\t\ts->ls_files_zeroed ? printf(\"%schangetype:%s%c\", pfx, one, 0) :\n \t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n+\t\ts->ls_files_zeroed ? printf(\"%sunknown:%s%c\", pfx, one, 0) :\n \t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n+\t\ts->ls_files_zeroed ? printf(\"%sunmerged:%s%c\", pfx, one, 0) :\n \t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n \t\tbreak;\n \tdefault:\n \t\tdie(\"bug: unhandled diff status %c\", p->status);\n \t}\n-\tfprintf(s->fp, \"\\n\");\n+\tif (!s->ls_files_zeroed)\n+\t\tfprintf(s->fp, \"\\n\");\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n@@ -143,14 +159,16 @@ static void wt_status_print_updated_cb(struct diff_queue_struct *q,\n \tfor (i = 0; i < q->nr; i++) {\n \t\tif (q->queue[i]->status == 'U')\n \t\t\tcontinue;\n-\t\tif (!shown_header) {\n-\t\t\twt_status_print_cached_header(s);\n-\t\t\ts->commitable = 1;\n-\t\t\tshown_header = 1;\n+\t\tif (!s->ls_files_zeroed) {\n+\t\t\tif (!shown_header) {\n+\t\t\t\twt_status_print_cached_header(s);\n+\t\t\t\ts->commitable = 1;\n+\t\t\t\tshown_header = 1;\n+\t\t\t}\n \t\t}\n \t\twt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);\n \t}\n-\tif (shown_header)\n+\tif (shown_header && !s->ls_files_zeroed)\n \t\twt_status_print_trailer(s);\n }\n \n@@ -163,16 +181,18 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,\n \tif (q->nr) {\n \t\tconst char *msg = use_add_msg;\n \t\ts->workdir_dirty = 1;\n-\t\tfor (i = 0; i < q->nr; i++)\n-\t\t\tif (q->queue[i]->status == DIFF_STATUS_DELETED) {\n-\t\t\t\tmsg = use_add_rm_msg;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\twt_status_print_header(s, \"Changed but not updated\", msg);\n+\t\tif (!s->ls_files_zeroed) {\n+\t\t\tfor (i = 0; i < q->nr; i++)\n+\t\t\t\tif (q->queue[i]->status == DIFF_STATUS_DELETED) {\n+\t\t\t\t\tmsg = use_add_rm_msg;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\twt_status_print_header(s, \"Changed but not updated\", msg);\n+\t\t}\n \t}\n \tfor (i = 0; i < q->nr; i++)\n \t\twt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);\n-\tif (q->nr)\n+\tif (q->nr && !s->ls_files_zeroed)\n \t\twt_status_print_trailer(s);\n }\n \n@@ -284,16 +304,21 @@ static void wt_status_print_untracked(struct wt_status *s)\n \t\t\t    !memcmp(ce->name, ent->name, ent->len))\n \t\t\t\tcontinue;\n \t\t}\n-\t\tif (!shown_header) {\n-\t\t\ts->workdir_untracked = 1;\n-\t\t\twt_status_print_header(s, \"Untracked files\",\n-\t\t\t\t\t       use_add_to_include_msg);\n-\t\t\tshown_header = 1;\n+\t\tif (s->ls_files_zeroed) {\n+\t\t\tprintf(\"untracked:%s%c\", make_path_relative(ent->name,\n+\t\t\t\tent->len, &buf, s->prefix), 0);\n+\t\t} else {\n+\t\t\tif (!shown_header) {\n+\t\t\t\ts->workdir_untracked = 1;\n+\t\t\t\twt_status_print_header(s, \"Untracked files\",\n+\t\t\t\t\t\t       use_add_to_include_msg);\n+\t\t\t\tshown_header = 1;\n+\t\t\t}\n+\t\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\t\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), \"%s\",\n+\t\t\t\t\tquote_path(ent->name, ent->len,\n+\t\t\t\t\t\t&buf, s->prefix));\n \t\t}\n-\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n-\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), \"%s\",\n-\t\t\t\tquote_path(ent->name, ent->len,\n-\t\t\t\t\t&buf, s->prefix));\n \t}\n \tstrbuf_release(&buf);\n }\n@@ -316,6 +341,14 @@ void wt_status_print(struct wt_status *s)\n \tunsigned char sha1[20];\n \ts->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;\n \n+\tif(s->ls_files_zeroed) {\n+\t\twt_status_print_updated(s);\n+\t\twt_status_print_changed(s);\n+\t\twt_status_print_untracked(s);\n+\t\treturn;\n+\t}\n+\n+\n \tif (s->branch) {\n \t\tconst char *on_what = \"On branch \";\n \t\tconst char *branch_name = s->branch;\ndiff --git a/wt-status.h b/wt-status.h\nindex 7d61410..7a02472 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -25,6 +25,7 @@ struct wt_status {\n \tconst char *index_file;\n \tFILE *fp;\n \tconst char *prefix;\n+\tint ls_files_zeroed;\n };\n \n int git_status_config(const char *var, const char *value);\n-- \n1.5.5.1\n"},{"id":"77173","messageId":"20080517025133.GQ29038@spearce.org","threadId":"13552","inReplyTo":"20080517023340.GG10006@kali.thurne.chezwam.org","subject":"Re: [PATCH] Add a -z option to 'git status' to safely feed shell programs with path names","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-05-17T02:51:33Z","receivedAt":"2008-05-17T02:51:33Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sebastien Gross <seb-git@chezwam.org> wrote:\n> Add a -z option to 'git status' to get a list of all files\n> but ignored, starting with modification type or 'untracked'\n> as prefix and ending with '\\0'.\n\nHmm.  Is the plumbing really that broken that you need to add -z\nsupport to porcelain rather than using the -z support already built\ninto the plumbing?\n \n>  * Remove all untracked files:\n> \n>    git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^untracked/ \\\n> \t{sub(\"^.+:\", \"\");print}' | xargs -0 -r rm\n\nThat I take it is just the long handed way to write `git clean -f` ?\n \n>  * List all updated file regardless the modification:\n> \n>    git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^updated/ \\\n> \t{sub(\"^.+:\", \"\");print}' | xargs -0 -n 1\n\nAnd this is just the long handed way to write `git diff --name-only` ?\n\n\nA very large and intrusive looking patch for what can already be\nobtained easier through existing, stable porcelain.  Not something\nI am in favor of seeing added at this time.\n\n-- \nShawn.\n"},{"id":"77183","messageId":"alpine.DEB.1.00.0805171109000.30431@racer","threadId":"13552","inReplyTo":"20080517025133.GQ29038@spearce.org","subject":"Re: [PATCH] Add a -z option to 'git status' to safely feed shell programs with path names","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-05-17T10:14:01Z","receivedAt":"2008-05-17T10:14:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 16 May 2008, Shawn O. Pearce wrote:\n\n> Sebastien Gross <seb-git@chezwam.org> wrote:\n> > Add a -z option to 'git status' to get a list of all files\n> > but ignored, starting with modification type or 'untracked'\n> > as prefix and ending with '\\0'.\n> \n> Hmm.  Is the plumbing really that broken that you need to add -z support \n> to porcelain rather than using the -z support already built into the \n> plumbing?\n\nTo answer the retorical question: no, it is not.  git ls-files already has \nthe \"-z\" flag, and we even have the scripts in contrib/examples/ to prove \nthat it works very fine, thankyouverymuch.\n\nJust as an example: this ugly, long line\n\ngit status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^untracked/ \\\n        {sub(\"^.+:\", \"\");print}' | xargs -0 -r rm\n\ncould be expressed like this:\n\ngit ls-files --others -z | xargs -0 -r rm\n\nI believe.  If not, this should provide a good starting point, without \nchanging Git at all!\n\n> A very large and intrusive looking patch for what can already be \n> obtained easier through existing, stable porcelain.  Not something I am \n> in favor of seeing added at this time.\n\nIt is not only intrusive looking.  It is sneaky: it changes git-commit at \nthe same time, even if you would not begin to guess from the shortline.\n\nIt adds a function that is clearly path-related into quote.c!\n\nAnd then, the commit message is quite different from the other commit \nmessages in git.git, no?\n\nOpposed to the patch,\nDscho\n"},{"id":"77186","messageId":"20080517102600.GA10290@glandium.org","threadId":"13552","inReplyTo":"alpine.DEB.1.00.0805171109000.30431@racer","subject":"Re: [PATCH] Add a -z option to 'git status' to safely feed shell programs with path names","fromName":"Mike Hommey","fromEmail":"mh@glandium.org","sentAt":"2008-05-17T10:26:00Z","receivedAt":"2008-05-17T10:26:00Z","isPatch":true,"sender":{"key":"mh@glandium.org","avatar":"https://avatars.githubusercontent.com/u/1038527?v=4"},"body":"On Sat, May 17, 2008 at 11:14:01AM +0100, Johannes Schindelin wrote:\n> Hi,\n> \n> On Fri, 16 May 2008, Shawn O. Pearce wrote:\n> \n> > Sebastien Gross <seb-git@chezwam.org> wrote:\n> > > Add a -z option to 'git status' to get a list of all files\n> > > but ignored, starting with modification type or 'untracked'\n> > > as prefix and ending with '\\0'.\n> > \n> > Hmm.  Is the plumbing really that broken that you need to add -z support \n> > to porcelain rather than using the -z support already built into the \n> > plumbing?\n> \n> To answer the retorical question: no, it is not.  git ls-files already has \n> the \"-z\" flag, and we even have the scripts in contrib/examples/ to prove \n> that it works very fine, thankyouverymuch.\n> \n> Just as an example: this ugly, long line\n> \n> git status -z | gawk 'BEGIN{RS=\"\\0\"; ORS=\"\\0\";}/^untracked/ \\\n>         {sub(\"^.+:\", \"\");print}' | xargs -0 -r rm\n> \n> could be expressed like this:\n> \n> git ls-files --others -z | xargs -0 -r rm\n\nor git clean -f\n\nMike\n"},{"id":"77187","messageId":"alpine.DEB.1.00.0805171201420.30431@racer","threadId":"13552","inReplyTo":"20080517102600.GA10290@glandium.org","subject":"Re: [PATCH] Add a -z option to 'git status' to safely feed shell programs with path names","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-05-17T11:02:51Z","receivedAt":"2008-05-17T11:02:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 17 May 2008, Mike Hommey wrote:\n\n> On Sat, May 17, 2008 at 11:14:01AM +0100, Johannes Schindelin wrote:\n>\n> > git ls-files --others -z | xargs -0 -r rm\n> \n> or git clean -f\n\n>From how I understood Sebastian, I thought he wanted to script Git, not \nonly to execute git clean.  And we pride ourselves in having one of the \nmost scriptable SCM ever.\n\nSo I thought I'd give him the proper _scriptable_ way to express things.\n\nCiao,\nDscho\n"}]}