{"thread":{"id":"21261","subject":"Q: supplying large sets of path to git commands","startedAt":"2009-10-16T10:40:23Z","lastAt":"2009-10-16T22:08:07Z","messageCount":2,"participants":["Constantine Plotnikov","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"125156","messageId":"85647ef50910160340s5b608d9cmb13679d7c6a987cd@mail.gmail.com","threadId":"21261","inReplyTo":null,"subject":"Q: supplying large sets of path to git commands","fromName":"Constantine Plotnikov","fromEmail":"constantine.plotnikov@gmail.com","sentAt":"2009-10-16T10:40:23Z","receivedAt":"2009-10-16T10:40:23Z","isPatch":false,"sender":{"key":"constantine.plotnikov@gmail.com","avatar":null},"body":"Some git commands like git check-attr supports receiving paths from\nstdin. For other commands like \"git diff\" and \"git commit --only\" I\nhave not found a way to supply a lot of paths (say 1000). Is there a\nstandard way pass a additional paths to git commands that works on\nwindows and unix? It would be nice to have --stdin option for all\ncommands that might receive a set of paths. Or even better would\nsomething like \"--options-from-stdin\" and\n\"--options-from-file=file.txt\" as a possible last argument specified\non the command line.\n\nConstantine\n"},{"id":"125212","messageId":"7vtyxzrnzs.fsf@alter.siamese.dyndns.org","threadId":"21261","inReplyTo":"85647ef50910160340s5b608d9cmb13679d7c6a987cd@mail.gmail.com","subject":"Re: Q: supplying large sets of path to git commands","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-16T22:08:07Z","receivedAt":"2009-10-16T22:08:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Constantine Plotnikov <constantine.plotnikov@gmail.com> writes:\n\n> Some git commands like git check-attr supports receiving paths from\n> stdin.\n\nHere is how one might implement it for diff/log family of commands that\nuse \"setup_revisions()\".\n\nI didn't test it (of course) beyond running \n\n    ./git diff --name-only HEAD | ./git diff --stdin-paths --stat -p\n\nin order to include the patch text in this message, and running\n\n    ./git diff --name-only | ./git log --stdin-paths --no-merges --stat\n\n---\n Documentation/git-rev-list.txt     |    1 +\n Documentation/rev-list-options.txt |    7 ++++\n revision.c                         |   59 +++++++++++++++++++++++++++++++++--\n 3 files changed, 63 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 3341d1b..8fa276c 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -46,6 +46,7 @@ SYNOPSIS\n \t     [ \\--reverse ]\n \t     [ \\--walk-reflogs ]\n \t     [ \\--no-walk ] [ \\--do-walk ]\n+\t     [ \\--stdin-paths | \\--stdin-paths-z ]\n \t     <commit>... [ \\-- <paths>... ]\n \n DESCRIPTION\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex bf66116..9960de8 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -317,6 +317,13 @@ The following options select the commits to be shown:\n \n \tCommits modifying the given <paths> are selected.\n \n+--stdin-paths::\n+--stdin-paths-z::\n+\n+\tAdditionally read <paths> (see above) from the standard input,\n+\tone path per line terminated with linefeed (or NUL when\n+\t--stdin-paths-z is used).\n+\n --simplify-by-decoration::\n \n \tCommits that are referred by some branch or tag are selected.\ndiff --git a/revision.c b/revision.c\nindex 9fc4e8d..4caccdb 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1218,6 +1218,38 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,\n \tctx->argc -= n;\n }\n \n+enum append_stdin_mode {\n+\tAPPEND_STDIN = 1,\n+\tAPPEND_STDIN_Z = 2,\n+};\n+\n+static const char **grab_pathspec(const char *prefix, const char **argv,\n+\t\t\t\t  enum append_stdin_mode append_stdin)\n+{\n+\tconst char **nargv;\n+\tint cnt, alloc, term;\n+\tstruct strbuf line = STRBUF_INIT;\n+\n+\tif (!append_stdin)\n+\t\treturn get_pathspec(prefix, argv);\n+\n+\tfor (cnt = 0; argv[cnt]; cnt++)\n+\t\t; /* first count */\n+\talloc = alloc_nr(cnt);\n+\tnargv = xmalloc(sizeof(*nargv) * alloc);\n+\tfor (cnt = 0; argv[cnt]; cnt++)\n+\t\tnargv[cnt] = argv[cnt]; /* then copy */\n+\n+\tterm = (append_stdin == APPEND_STDIN_Z) ? '\\0' : '\\n';\n+\twhile (strbuf_getline(&line, stdin, term) != EOF) {\n+\t\tALLOC_GROW(nargv, cnt, alloc);\n+\t\tnargv[cnt++] = strbuf_detach(&line, NULL);\n+\t}\n+\tALLOC_GROW(nargv, cnt, alloc);\n+\tnargv[cnt] = NULL;\n+\treturn get_pathspec(prefix, nargv);\n+}\n+\n /*\n  * Parse revision information, filling in the \"rev_info\" structure,\n  * and removing the used arguments from the argument list.\n@@ -1228,17 +1260,26 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,\n int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def)\n {\n \tint i, flags, left, seen_dashdash;\n+\tenum append_stdin_mode append_stdin = 0;\n \n-\t/* First, search for \"--\" */\n+\t/* First, search for \"--\", \"--stdin-paths\", and \"--stdin-paths-z\" */\n \tseen_dashdash = 0;\n \tfor (i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n+\n+\t\tif (!strcmp(arg, \"--stdin-paths\"))\n+\t\t\tappend_stdin = APPEND_STDIN;\n+\t\telse if (!strcmp(arg, \"--stdin-paths-z\"))\n+\t\t\tappend_stdin = APPEND_STDIN_Z;\n+\n \t\tif (strcmp(arg, \"--\"))\n \t\t\tcontinue;\n \t\targv[i] = NULL;\n \t\targc = i;\n \t\tif (argv[i + 1])\n-\t\t\trevs->prune_data = get_pathspec(revs->prefix, argv + i + 1);\n+\t\t\trevs->prune_data = grab_pathspec(revs->prefix,\n+\t\t\t\t\t\t\t argv + i + 1,\n+\t\t\t\t\t\t\t append_stdin);\n \t\tseen_dashdash = 1;\n \t\tbreak;\n \t}\n@@ -1283,6 +1324,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\trevs->no_walk = 0;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--stdin-paths\") ||\n+\t\t\t    !strcmp(arg, \"--stdin-paths-z\"))\n+\t\t\t\tcontinue; /* already handled */\n \n \t\t\topts = handle_revision_opt(revs, argc - i, argv + i, &left, argv);\n \t\t\tif (opts > 0) {\n@@ -1308,12 +1352,19 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\tfor (j = i; j < argc; j++)\n \t\t\t\tverify_filename(revs->prefix, argv[j]);\n \n-\t\t\trevs->prune_data = get_pathspec(revs->prefix,\n-\t\t\t\t\t\t\targv + i);\n+\t\t\trevs->prune_data = grab_pathspec(revs->prefix,\n+\t\t\t\t\t\t\t argv + i,\n+\t\t\t\t\t\t\t append_stdin);\n \t\t\tbreak;\n \t\t}\n \t}\n \n+\tif (!revs->prune_data && append_stdin) {\n+\t\tconst char *empty_argv[1] = { NULL };\n+\t\trevs->prune_data = grab_pathspec(revs->prefix, empty_argv,\n+\t\t\t\t\t\t append_stdin);\n+\t}\n+\n \tif (revs->def == NULL)\n \t\trevs->def = def;\n \tif (revs->show_merge)\n"}]}