{"thread":{"id":"19856","subject":"I'd like to be able to know what git-push will do","startedAt":"2009-06-18T21:28:03Z","lastAt":"2009-06-27T00:23:17Z","messageCount":13,"participants":["Larry D'Anna","Jeff King","Marc Branchaud","Junio C Hamano","Markus Heidelberg","Constantine Plotnikov"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"116600","messageId":"20090618212803.GA14486@cthulhu","threadId":"19856","inReplyTo":null,"subject":"I'd like to be able to know what git-push will do","fromName":"Larry D'Anna","fromEmail":"larry@elder-gods.org","sentAt":"2009-06-18T21:28:03Z","receivedAt":"2009-06-18T21:28:03Z","isPatch":false,"sender":{"key":"larry@elder-gods.org","avatar":"https://avatars.githubusercontent.com/u/3013304?v=4"},"body":"I previously sent this to Junio, but I think I should have just sent it to the\nlist.\n\nI'd like to be able to call git-push --dry-run and process the result from a\nperl script, but there's a snag: what does \"foobar -> foobar\" mean?  foobar\ncould be a tag or a branch.  In fact, it could be a branch on on side and a tag\non the other!  \n\nI've tried duplicating the refspec processing in the perl script, but this\napproach is highly sub-optimal because the refspec parsing and matching is so\ncomplicated.  I would wind up duplicating a lot of functionality, and every time\nit changed in git my script would become broken.\n\nWould you accept a patch that changes the behavior of git-push so that instead of\n\n  $ git-push --dry-run  -v origin :\n  Pushing to ~/repos/bin\n  To ~/repos/bin\n   = [up to date]      master -> master\n  Everything up-to-date\n  \nIt would print the full names like this (only if -v is used)\n\n  $ git-push --dry-run  -v origin :\n  Pushing to ~/repos/bin\n  To ~/repos/bin\n   = [up to date]      refs/heads/master -> refs/heads/master\n  Everything up-to-date\n\nOr, if you don't like changing the behavior of -v, would you accept a patch with\na new option (perhaps --symbolic-full-name) that caused git-push to behave this\nway?\n\nOnce I know what the user interface should be (-v or --symbolic-full-name or\nwhatever) I'll post a patch.\n\nThanks!\n\n        --larry\n"},{"id":"116790","messageId":"20090622214032.GC19364@coredump.intra.peff.net","threadId":"19856","inReplyTo":"20090618212803.GA14486@cthulhu","subject":"Re: I'd like to be able to know what git-push will do","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-06-22T21:40:32Z","receivedAt":"2009-06-22T21:40:32Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jun 18, 2009 at 05:28:03PM -0400, Larry D'Anna wrote:\n\n> I'd like to be able to call git-push --dry-run and process the result\n> from a perl script, but there's a snag: what does \"foobar -> foobar\"\n> mean?  foobar could be a tag or a branch.  In fact, it could be a\n> branch on on side and a tag on the other!\n\nYeah, that output is really meant for human consumption.\n\n> I've tried duplicating the refspec processing in the perl script, but\n> this approach is highly sub-optimal because the refspec parsing and\n> matching is so complicated.  I would wind up duplicating a lot of\n> functionality, and every time it changed in git my script would become\n> broken.\n\nAgreed.\n\n> Would you accept a patch that changes the behavior of git-push so that\n> instead of\n> \n>   $ git-push --dry-run  -v origin :\n>   Pushing to ~/repos/bin\n>   To ~/repos/bin\n>    = [up to date]      master -> master\n>   Everything up-to-date\n>   \n> It would print the full names like this (only if -v is used)\n> \n>   $ git-push --dry-run  -v origin :\n>   Pushing to ~/repos/bin\n>   To ~/repos/bin\n>    = [up to date]      refs/heads/master -> refs/heads/master\n>   Everything up-to-date\n> \n> Or, if you don't like changing the behavior of -v, would you accept a\n> patch with a new option (perhaps --symbolic-full-name) that caused\n> git-push to behave this way?\n\nI think it would have to be a new option, as \"-v\" is really about\nsomething orthogonal. However, I actually think you are better off\nmaking a whole new output format for porcelain scripts to read. As I\nsaid, the current output is for human consumption, and I wouldn't rule\nout the possibility of it changing in the future (and it won't receive\nthe same sort of deprecation treatment that an interface created for\nscripts would get).\n\nIn other words, something like:\n\n  $ git push --dry-run --porcelain origin :\n  =refs/heads/master:refs/heads/master\n\n(the format is totally off the top of my head -- I haven't thought too\nlong about what you might want to have in it).\n\n-Peff\n"},{"id":"116797","messageId":"20090623011001.GA15352@cthulhu","threadId":"19856","inReplyTo":"20090622214032.GC19364@coredump.intra.peff.net","subject":"[PATCH] add --porcelain option to git-push","fromName":"Larry D'Anna","fromEmail":"larry@elder-gods.org","sentAt":"2009-06-23T01:10:01Z","receivedAt":"2009-06-23T01:10:01Z","isPatch":true,"sender":{"key":"larry@elder-gods.org","avatar":"https://avatars.githubusercontent.com/u/3013304?v=4"},"body":"If --porcelain is used git-push will produce machine-readable output.  The\noutput status line for each ref will be tab-separated and sent to stdout instead\nof stderr.  The full symbolic names of the refs will be given.  For example\n\n$ git push --dry-run --porcelain master :foobar 2>/dev/null \\\n  | perl -pe 's/\\t/ TAB /g'\n\n= TAB refs/heads/master:refs/heads/master TAB [up to date]\n- TAB :refs/heads/foobar TAB [deleted]\n---\n Documentation/git-push.txt |   11 ++++++\n builtin-push.c             |    3 +-\n transport.c                |   75 +++++++++++++++++++++++++------------------\n transport.h                |    1 +\n 4 files changed, 58 insertions(+), 32 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex fd53c49..2653388 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).\n --dry-run::\n \tDo everything except actually send the updates.\n \n+--porcelain::\n+\tProduce machine-readable output.  The output status line for each ref\n+\twill be tab-separated and sent to stdout instead of stderr.  The full\n+\tsymbolic names of the refs will be given.\n+\n --tags::\n \tAll refs under `$GIT_DIR/refs/tags` are pushed, in\n \taddition to refspecs explicitly listed on the command\n@@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:\n  <flag> <summary> <from> -> <to> (<reason>)\n -------------------------------\n \n+If --porcelain is used, then each line of the output is of the form:\n+\n+-------------------------------\n+ <flag> \\t <from>:<to> \\t <summary> (<reason>)\n+-------------------------------\n+\n flag::\n \tA single character indicating the status of the ref. This is\n \tblank for a successfully pushed ref, `!` for a ref that was\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 7be1239..0a0297f 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,7 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n \tNULL,\n };\n \n@@ -200,6 +200,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n \t\tOPT_BIT( 0 , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n+\t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n \t\tOPT_BIT('f', \"force\", &flags, \"force updates\", TRANSPORT_PUSH_FORCE),\n \t\tOPT_BOOLEAN( 0 , \"thin\", &thin, \"use thin pack\"),\n \t\tOPT_STRING( 0 , \"receive-pack\", &receivepack, \"receive-pack\", \"receive pack program\"),\ndiff --git a/transport.c b/transport.c\nindex 501a77b..b074067 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -719,19 +719,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb\n \n #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)\n \n-static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)\n+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)\n {\n-\tfprintf(stderr, \" %c %-*s \", flag, SUMMARY_WIDTH, summary);\n-\tif (from)\n-\t\tfprintf(stderr, \"%s -> %s\", prettify_refname(from->name), prettify_refname(to->name));\n-\telse\n-\t\tfputs(prettify_refname(to->name), stderr);\n-\tif (msg) {\n-\t\tfputs(\" (\", stderr);\n-\t\tfputs(msg, stderr);\n-\t\tfputc(')', stderr);\n+\tif (porcelain) {\n+\t\tif (from)\n+\t\t\tfprintf(stdout, \"%c\\t%s:%s\\t\", flag, from->name, to->name);\n+\t\telse\n+\t\t\tfprintf(stdout, \"%c\\t:%s\\t\", flag, to->name);\n+\t\tif (msg)\n+\t\t\tfprintf(stdout, \"%s (%s)\\n\", summary, msg);\n+\t\telse\n+\t\t\tfprintf(stdout, \"%s\\n\", summary);\n+\t} else {\n+\t\tfprintf(stderr, \" %c %-*s \", flag, SUMMARY_WIDTH, summary);\n+\t\tif (from)\n+\t\t\tfprintf(stderr, \"%s -> %s\", prettify_refname(from->name), prettify_refname(to->name));\n+\t\telse\n+\t\t\tfputs(prettify_refname(to->name), stderr);\n+\t\tif (msg) {\n+\t\t\tfputs(\" (\", stderr);\n+\t\t\tfputs(msg, stderr);\n+\t\t\tfputc(')', stderr);\n+\t\t}\n+\t\tfputc('\\n', stderr);\n \t}\n-\tfputc('\\n', stderr);\n }\n \n static const char *status_abbrev(unsigned char sha1[20])\n@@ -739,15 +750,15 @@ static const char *status_abbrev(unsigned char sha1[20])\n \treturn find_unique_abbrev(sha1, DEFAULT_ABBREV);\n }\n \n-static void print_ok_ref_status(struct ref *ref)\n+static void print_ok_ref_status(struct ref *ref, int porcelain)\n {\n \tif (ref->deletion)\n-\t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL);\n+\t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL, porcelain);\n \telse if (is_null_sha1(ref->old_sha1))\n \t\tprint_ref_status('*',\n \t\t\t(!prefixcmp(ref->name, \"refs/tags/\") ? \"[new tag]\" :\n-\t\t\t  \"[new branch]\"),\n-\t\t\tref, ref->peer_ref, NULL);\n+\t\t\t\"[new branch]\"),\n+\t\t\tref, ref->peer_ref, NULL, porcelain);\n \telse {\n \t\tchar quickref[84];\n \t\tchar type;\n@@ -765,50 +776,51 @@ static void print_ok_ref_status(struct ref *ref)\n \t\t}\n \t\tstrcat(quickref, status_abbrev(ref->new_sha1));\n \n-\t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg);\n+\t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);\n \t}\n }\n \n-static int print_one_push_status(struct ref *ref, const char *dest, int count)\n+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)\n {\n \tif (!count)\n \t\tfprintf(stderr, \"To %s\\n\", dest);\n \n \tswitch(ref->status) {\n \tcase REF_STATUS_NONE:\n-\t\tprint_ref_status('X', \"[no match]\", ref, NULL, NULL);\n+\t\tprint_ref_status('X', \"[no match]\", ref, NULL, NULL, porcelain);\n \t\tbreak;\n \tcase REF_STATUS_REJECT_NODELETE:\n \t\tprint_ref_status('!', \"[rejected]\", ref, NULL,\n-\t\t\t\t\"remote does not support deleting refs\");\n+\t\t\t\t\t\t \"remote does not support deleting refs\", porcelain);\n \t\tbreak;\n \tcase REF_STATUS_UPTODATE:\n \t\tprint_ref_status('=', \"[up to date]\", ref,\n-\t\t\t\tref->peer_ref, NULL);\n+\t\t\t\t\t\t ref->peer_ref, NULL, porcelain);\n \t\tbreak;\n \tcase REF_STATUS_REJECT_NONFASTFORWARD:\n \t\tprint_ref_status('!', \"[rejected]\", ref, ref->peer_ref,\n-\t\t\t\t\"non-fast forward\");\n+\t\t\t\t\t\t \"non-fast forward\", porcelain);\n \t\tbreak;\n \tcase REF_STATUS_REMOTE_REJECT:\n \t\tprint_ref_status('!', \"[remote rejected]\", ref,\n-\t\t\t\tref->deletion ? NULL : ref->peer_ref,\n-\t\t\t\tref->remote_status);\n+\t\t\t\t\t\t ref->deletion ? NULL : ref->peer_ref,\n+\t\t\t\t\t\t ref->remote_status, porcelain);\n \t\tbreak;\n \tcase REF_STATUS_EXPECTING_REPORT:\n \t\tprint_ref_status('!', \"[remote failure]\", ref,\n-\t\t\t\tref->deletion ? NULL : ref->peer_ref,\n-\t\t\t\t\"remote failed to report status\");\n+\t\t\t\t\t\t ref->deletion ? NULL : ref->peer_ref,\n+\t\t\t\t\t\t \"remote failed to report status\", porcelain);\n \t\tbreak;\n \tcase REF_STATUS_OK:\n-\t\tprint_ok_ref_status(ref);\n+\t\tprint_ok_ref_status(ref, porcelain);\n \t\tbreak;\n \t}\n \n \treturn 1;\n }\n \n-static void print_push_status(const char *dest, struct ref *refs, int verbose)\n+static void print_push_status(const char *dest, struct ref *refs,\n+\t\t\t\t\t\t\t  int verbose, int porcelain)\n {\n \tstruct ref *ref;\n \tint n = 0;\n@@ -816,18 +828,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)\n \tif (verbose) {\n \t\tfor (ref = refs; ref; ref = ref->next)\n \t\t\tif (ref->status == REF_STATUS_UPTODATE)\n-\t\t\t\tn += print_one_push_status(ref, dest, n);\n+\t\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n \t}\n \n \tfor (ref = refs; ref; ref = ref->next)\n \t\tif (ref->status == REF_STATUS_OK)\n-\t\t\tn += print_one_push_status(ref, dest, n);\n+\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n \n \tfor (ref = refs; ref; ref = ref->next) {\n \t\tif (ref->status != REF_STATUS_NONE &&\n \t\t    ref->status != REF_STATUS_UPTODATE &&\n \t\t    ref->status != REF_STATUS_OK)\n-\t\t\tn += print_one_push_status(ref, dest, n);\n+\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n \t}\n }\n \n@@ -997,6 +1009,7 @@ int transport_push(struct transport *transport,\n \t\tstruct ref *local_refs = get_local_heads();\n \t\tint match_flags = MATCH_REFS_NONE;\n \t\tint verbose = flags & TRANSPORT_PUSH_VERBOSE;\n+\t\tint porcelain = flags & TRANSPORT_PUSH_PORCELAIN;\n \t\tint ret;\n \n \t\tif (flags & TRANSPORT_PUSH_ALL)\n@@ -1011,7 +1024,7 @@ int transport_push(struct transport *transport,\n \n \t\tret = transport->push_refs(transport, remote_refs, flags);\n \n-\t\tprint_push_status(transport->url, remote_refs, verbose);\n+\t\tprint_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);\n \n \t\tif (!(flags & TRANSPORT_PUSH_DRY_RUN)) {\n \t\t\tstruct ref *ref;\ndiff --git a/transport.h b/transport.h\nindex 27bfc52..51b5397 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -35,6 +35,7 @@ struct transport {\n #define TRANSPORT_PUSH_DRY_RUN 4\n #define TRANSPORT_PUSH_MIRROR 8\n #define TRANSPORT_PUSH_VERBOSE 16\n+#define TRANSPORT_PUSH_PORCELAIN 32\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n-- \n1.6.0.4\n"},{"id":"116821","messageId":"4A40EF9C.7000706@xiplink.com","threadId":"19856","inReplyTo":"20090623011001.GA15352@cthulhu","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2009-06-23T15:07:08Z","receivedAt":"2009-06-23T15:07:08Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"Shouldn't this option be named \"--plumbing\" since it's making 'git push' act like plumbing?  Actually, neither name seems intuitively descriptive to me...\n\nWhy not teach 'git push' to change its output format if it's writing to a pipe?\n\n\t\tM.\n\n\nLarry D'Anna wrote:\n> If --porcelain is used git-push will produce machine-readable output.  The\n> output status line for each ref will be tab-separated and sent to stdout instead\n> of stderr.  The full symbolic names of the refs will be given.  For example\n> \n> $ git push --dry-run --porcelain master :foobar 2>/dev/null \\\n>   | perl -pe 's/\\t/ TAB /g'\n> \n> = TAB refs/heads/master:refs/heads/master TAB [up to date]\n> - TAB :refs/heads/foobar TAB [deleted]\n> ---\n>  Documentation/git-push.txt |   11 ++++++\n>  builtin-push.c             |    3 +-\n>  transport.c                |   75 +++++++++++++++++++++++++------------------\n>  transport.h                |    1 +\n>  4 files changed, 58 insertions(+), 32 deletions(-)\n> \n> diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\n> index fd53c49..2653388 100644\n> --- a/Documentation/git-push.txt\n> +++ b/Documentation/git-push.txt\n> @@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).\n>  --dry-run::\n>  \tDo everything except actually send the updates.\n>  \n> +--porcelain::\n> +\tProduce machine-readable output.  The output status line for each ref\n> +\twill be tab-separated and sent to stdout instead of stderr.  The full\n> +\tsymbolic names of the refs will be given.\n> +\n>  --tags::\n>  \tAll refs under `$GIT_DIR/refs/tags` are pushed, in\n>  \taddition to refspecs explicitly listed on the command\n> @@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:\n>   <flag> <summary> <from> -> <to> (<reason>)\n>  -------------------------------\n>  \n> +If --porcelain is used, then each line of the output is of the form:\n> +\n> +-------------------------------\n> + <flag> \\t <from>:<to> \\t <summary> (<reason>)\n> +-------------------------------\n> +\n>  flag::\n>  \tA single character indicating the status of the ref. This is\n>  \tblank for a successfully pushed ref, `!` for a ref that was\n> diff --git a/builtin-push.c b/builtin-push.c\n> index 7be1239..0a0297f 100644\n> --- a/builtin-push.c\n> +++ b/builtin-push.c\n> @@ -10,7 +10,7 @@\n>  #include \"parse-options.h\"\n>  \n>  static const char * const push_usage[] = {\n> -\t\"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n> +\t\"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n>  \tNULL,\n>  };\n>  \n> @@ -200,6 +200,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n>  \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n>  \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n>  \t\tOPT_BIT( 0 , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n> +\t\tOPT_BIT( 0,  \"porcelain\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PORCELAIN),\n>  \t\tOPT_BIT('f', \"force\", &flags, \"force updates\", TRANSPORT_PUSH_FORCE),\n>  \t\tOPT_BOOLEAN( 0 , \"thin\", &thin, \"use thin pack\"),\n>  \t\tOPT_STRING( 0 , \"receive-pack\", &receivepack, \"receive-pack\", \"receive pack program\"),\n> diff --git a/transport.c b/transport.c\n> index 501a77b..b074067 100644\n> --- a/transport.c\n> +++ b/transport.c\n> @@ -719,19 +719,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb\n>  \n>  #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)\n>  \n> -static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)\n> +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)\n>  {\n> -\tfprintf(stderr, \" %c %-*s \", flag, SUMMARY_WIDTH, summary);\n> -\tif (from)\n> -\t\tfprintf(stderr, \"%s -> %s\", prettify_refname(from->name), prettify_refname(to->name));\n> -\telse\n> -\t\tfputs(prettify_refname(to->name), stderr);\n> -\tif (msg) {\n> -\t\tfputs(\" (\", stderr);\n> -\t\tfputs(msg, stderr);\n> -\t\tfputc(')', stderr);\n> +\tif (porcelain) {\n> +\t\tif (from)\n> +\t\t\tfprintf(stdout, \"%c\\t%s:%s\\t\", flag, from->name, to->name);\n> +\t\telse\n> +\t\t\tfprintf(stdout, \"%c\\t:%s\\t\", flag, to->name);\n> +\t\tif (msg)\n> +\t\t\tfprintf(stdout, \"%s (%s)\\n\", summary, msg);\n> +\t\telse\n> +\t\t\tfprintf(stdout, \"%s\\n\", summary);\n> +\t} else {\n> +\t\tfprintf(stderr, \" %c %-*s \", flag, SUMMARY_WIDTH, summary);\n> +\t\tif (from)\n> +\t\t\tfprintf(stderr, \"%s -> %s\", prettify_refname(from->name), prettify_refname(to->name));\n> +\t\telse\n> +\t\t\tfputs(prettify_refname(to->name), stderr);\n> +\t\tif (msg) {\n> +\t\t\tfputs(\" (\", stderr);\n> +\t\t\tfputs(msg, stderr);\n> +\t\t\tfputc(')', stderr);\n> +\t\t}\n> +\t\tfputc('\\n', stderr);\n>  \t}\n> -\tfputc('\\n', stderr);\n>  }\n>  \n>  static const char *status_abbrev(unsigned char sha1[20])\n> @@ -739,15 +750,15 @@ static const char *status_abbrev(unsigned char sha1[20])\n>  \treturn find_unique_abbrev(sha1, DEFAULT_ABBREV);\n>  }\n>  \n> -static void print_ok_ref_status(struct ref *ref)\n> +static void print_ok_ref_status(struct ref *ref, int porcelain)\n>  {\n>  \tif (ref->deletion)\n> -\t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL);\n> +\t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL, porcelain);\n>  \telse if (is_null_sha1(ref->old_sha1))\n>  \t\tprint_ref_status('*',\n>  \t\t\t(!prefixcmp(ref->name, \"refs/tags/\") ? \"[new tag]\" :\n> -\t\t\t  \"[new branch]\"),\n> -\t\t\tref, ref->peer_ref, NULL);\n> +\t\t\t\"[new branch]\"),\n> +\t\t\tref, ref->peer_ref, NULL, porcelain);\n>  \telse {\n>  \t\tchar quickref[84];\n>  \t\tchar type;\n> @@ -765,50 +776,51 @@ static void print_ok_ref_status(struct ref *ref)\n>  \t\t}\n>  \t\tstrcat(quickref, status_abbrev(ref->new_sha1));\n>  \n> -\t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg);\n> +\t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);\n>  \t}\n>  }\n>  \n> -static int print_one_push_status(struct ref *ref, const char *dest, int count)\n> +static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)\n>  {\n>  \tif (!count)\n>  \t\tfprintf(stderr, \"To %s\\n\", dest);\n>  \n>  \tswitch(ref->status) {\n>  \tcase REF_STATUS_NONE:\n> -\t\tprint_ref_status('X', \"[no match]\", ref, NULL, NULL);\n> +\t\tprint_ref_status('X', \"[no match]\", ref, NULL, NULL, porcelain);\n>  \t\tbreak;\n>  \tcase REF_STATUS_REJECT_NODELETE:\n>  \t\tprint_ref_status('!', \"[rejected]\", ref, NULL,\n> -\t\t\t\t\"remote does not support deleting refs\");\n> +\t\t\t\t\t\t \"remote does not support deleting refs\", porcelain);\n>  \t\tbreak;\n>  \tcase REF_STATUS_UPTODATE:\n>  \t\tprint_ref_status('=', \"[up to date]\", ref,\n> -\t\t\t\tref->peer_ref, NULL);\n> +\t\t\t\t\t\t ref->peer_ref, NULL, porcelain);\n>  \t\tbreak;\n>  \tcase REF_STATUS_REJECT_NONFASTFORWARD:\n>  \t\tprint_ref_status('!', \"[rejected]\", ref, ref->peer_ref,\n> -\t\t\t\t\"non-fast forward\");\n> +\t\t\t\t\t\t \"non-fast forward\", porcelain);\n>  \t\tbreak;\n>  \tcase REF_STATUS_REMOTE_REJECT:\n>  \t\tprint_ref_status('!', \"[remote rejected]\", ref,\n> -\t\t\t\tref->deletion ? NULL : ref->peer_ref,\n> -\t\t\t\tref->remote_status);\n> +\t\t\t\t\t\t ref->deletion ? NULL : ref->peer_ref,\n> +\t\t\t\t\t\t ref->remote_status, porcelain);\n>  \t\tbreak;\n>  \tcase REF_STATUS_EXPECTING_REPORT:\n>  \t\tprint_ref_status('!', \"[remote failure]\", ref,\n> -\t\t\t\tref->deletion ? NULL : ref->peer_ref,\n> -\t\t\t\t\"remote failed to report status\");\n> +\t\t\t\t\t\t ref->deletion ? NULL : ref->peer_ref,\n> +\t\t\t\t\t\t \"remote failed to report status\", porcelain);\n>  \t\tbreak;\n>  \tcase REF_STATUS_OK:\n> -\t\tprint_ok_ref_status(ref);\n> +\t\tprint_ok_ref_status(ref, porcelain);\n>  \t\tbreak;\n>  \t}\n>  \n>  \treturn 1;\n>  }\n>  \n> -static void print_push_status(const char *dest, struct ref *refs, int verbose)\n> +static void print_push_status(const char *dest, struct ref *refs,\n> +\t\t\t\t\t\t\t  int verbose, int porcelain)\n>  {\n>  \tstruct ref *ref;\n>  \tint n = 0;\n> @@ -816,18 +828,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)\n>  \tif (verbose) {\n>  \t\tfor (ref = refs; ref; ref = ref->next)\n>  \t\t\tif (ref->status == REF_STATUS_UPTODATE)\n> -\t\t\t\tn += print_one_push_status(ref, dest, n);\n> +\t\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n>  \t}\n>  \n>  \tfor (ref = refs; ref; ref = ref->next)\n>  \t\tif (ref->status == REF_STATUS_OK)\n> -\t\t\tn += print_one_push_status(ref, dest, n);\n> +\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n>  \n>  \tfor (ref = refs; ref; ref = ref->next) {\n>  \t\tif (ref->status != REF_STATUS_NONE &&\n>  \t\t    ref->status != REF_STATUS_UPTODATE &&\n>  \t\t    ref->status != REF_STATUS_OK)\n> -\t\t\tn += print_one_push_status(ref, dest, n);\n> +\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n>  \t}\n>  }\n>  \n> @@ -997,6 +1009,7 @@ int transport_push(struct transport *transport,\n>  \t\tstruct ref *local_refs = get_local_heads();\n>  \t\tint match_flags = MATCH_REFS_NONE;\n>  \t\tint verbose = flags & TRANSPORT_PUSH_VERBOSE;\n> +\t\tint porcelain = flags & TRANSPORT_PUSH_PORCELAIN;\n>  \t\tint ret;\n>  \n>  \t\tif (flags & TRANSPORT_PUSH_ALL)\n> @@ -1011,7 +1024,7 @@ int transport_push(struct transport *transport,\n>  \n>  \t\tret = transport->push_refs(transport, remote_refs, flags);\n>  \n> -\t\tprint_push_status(transport->url, remote_refs, verbose);\n> +\t\tprint_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);\n>  \n>  \t\tif (!(flags & TRANSPORT_PUSH_DRY_RUN)) {\n>  \t\t\tstruct ref *ref;\n> diff --git a/transport.h b/transport.h\n> index 27bfc52..51b5397 100644\n> --- a/transport.h\n> +++ b/transport.h\n> @@ -35,6 +35,7 @@ struct transport {\n>  #define TRANSPORT_PUSH_DRY_RUN 4\n>  #define TRANSPORT_PUSH_MIRROR 8\n>  #define TRANSPORT_PUSH_VERBOSE 16\n> +#define TRANSPORT_PUSH_PORCELAIN 32\n>  \n>  /* Returns a transport suitable for the url */\n>  struct transport *transport_get(struct remote *, const char *);\n"},{"id":"116823","messageId":"20090623153833.GA31853@cthulhu","threadId":"19856","inReplyTo":"4A40EF9C.7000706@xiplink.com","subject":"[PATCH] add --plumbing option to git-push","fromName":"Larry D'Anna","fromEmail":"larry@elder-gods.org","sentAt":"2009-06-23T15:38:33Z","receivedAt":"2009-06-23T15:38:33Z","isPatch":true,"sender":{"key":"larry@elder-gods.org","avatar":"https://avatars.githubusercontent.com/u/3013304?v=4"},"body":"If --plumbing is used git-push will produce machine-readable output.  The\noutput status line for each ref will be tab-separated and sent to stdout instead\nof stderr.  The full symbolic names of the refs will be given.  For example\n\n$ git push --dry-run --plumbing master :foobar 2>/dev/null \\\n  | perl -pe 's/\\t/ TAB /g'\n\n= TAB refs/heads/master:refs/heads/master TAB [up to date]\n- TAB :refs/heads/foobar TAB [deleted]\n---\n Documentation/git-push.txt |   11 ++++++\n builtin-push.c             |    3 +-\n transport.c                |   75 +++++++++++++++++++++++++------------------\n transport.h                |    1 +\n 4 files changed, 58 insertions(+), 32 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex fd53c49..9178145 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).\n --dry-run::\n \tDo everything except actually send the updates.\n \n+--plumbing::\n+\tProduce machine-readable output.  The output status line for each ref\n+\twill be tab-separated and sent to stdout instead of stderr.  The full\n+\tsymbolic names of the refs will be given.\n+\n --tags::\n \tAll refs under `$GIT_DIR/refs/tags` are pushed, in\n \taddition to refspecs explicitly listed on the command\n@@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:\n  <flag> <summary> <from> -> <to> (<reason>)\n -------------------------------\n \n+If --plumbing is used, then each line of the output is of the form:\n+\n+-------------------------------\n+ <flag> \\t <from>:<to> \\t <summary> (<reason>)\n+-------------------------------\n+\n flag::\n \tA single character indicating the status of the ref. This is\n \tblank for a successfully pushed ref, `!` for a ref that was\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 7be1239..845db1b 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,7 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git push [--all | --mirror] [--dry-run] [--plumbing] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]\",\n \tNULL,\n };\n \n@@ -200,6 +200,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\t\t    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n \t\tOPT_BIT( 0 , \"dry-run\", &flags, \"dry run\", TRANSPORT_PUSH_DRY_RUN),\n+\t\tOPT_BIT( 0,  \"plumbing\", &flags, \"machine-readable output\", TRANSPORT_PUSH_PLUMBING),\n \t\tOPT_BIT('f', \"force\", &flags, \"force updates\", TRANSPORT_PUSH_FORCE),\n \t\tOPT_BOOLEAN( 0 , \"thin\", &thin, \"use thin pack\"),\n \t\tOPT_STRING( 0 , \"receive-pack\", &receivepack, \"receive-pack\", \"receive pack program\"),\ndiff --git a/transport.c b/transport.c\nindex 501a77b..09d9baa 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -719,19 +719,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb\n \n #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)\n \n-static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)\n+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int plumbing)\n {\n-\tfprintf(stderr, \" %c %-*s \", flag, SUMMARY_WIDTH, summary);\n-\tif (from)\n-\t\tfprintf(stderr, \"%s -> %s\", prettify_refname(from->name), prettify_refname(to->name));\n-\telse\n-\t\tfputs(prettify_refname(to->name), stderr);\n-\tif (msg) {\n-\t\tfputs(\" (\", stderr);\n-\t\tfputs(msg, stderr);\n-\t\tfputc(')', stderr);\n+\tif (plumbing) {\n+\t\tif (from)\n+\t\t\tfprintf(stdout, \"%c\\t%s:%s\\t\", flag, from->name, to->name);\n+\t\telse\n+\t\t\tfprintf(stdout, \"%c\\t:%s\\t\", flag, to->name);\n+\t\tif (msg)\n+\t\t\tfprintf(stdout, \"%s (%s)\\n\", summary, msg);\n+\t\telse\n+\t\t\tfprintf(stdout, \"%s\\n\", summary);\n+\t} else {\n+\t\tfprintf(stderr, \" %c %-*s \", flag, SUMMARY_WIDTH, summary);\n+\t\tif (from)\n+\t\t\tfprintf(stderr, \"%s -> %s\", prettify_refname(from->name), prettify_refname(to->name));\n+\t\telse\n+\t\t\tfputs(prettify_refname(to->name), stderr);\n+\t\tif (msg) {\n+\t\t\tfputs(\" (\", stderr);\n+\t\t\tfputs(msg, stderr);\n+\t\t\tfputc(')', stderr);\n+\t\t}\n+\t\tfputc('\\n', stderr);\n \t}\n-\tfputc('\\n', stderr);\n }\n \n static const char *status_abbrev(unsigned char sha1[20])\n@@ -739,15 +750,15 @@ static const char *status_abbrev(unsigned char sha1[20])\n \treturn find_unique_abbrev(sha1, DEFAULT_ABBREV);\n }\n \n-static void print_ok_ref_status(struct ref *ref)\n+static void print_ok_ref_status(struct ref *ref, int plumbing)\n {\n \tif (ref->deletion)\n-\t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL);\n+\t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL, plumbing);\n \telse if (is_null_sha1(ref->old_sha1))\n \t\tprint_ref_status('*',\n \t\t\t(!prefixcmp(ref->name, \"refs/tags/\") ? \"[new tag]\" :\n-\t\t\t  \"[new branch]\"),\n-\t\t\tref, ref->peer_ref, NULL);\n+\t\t\t\"[new branch]\"),\n+\t\t\tref, ref->peer_ref, NULL, plumbing);\n \telse {\n \t\tchar quickref[84];\n \t\tchar type;\n@@ -765,50 +776,51 @@ static void print_ok_ref_status(struct ref *ref)\n \t\t}\n \t\tstrcat(quickref, status_abbrev(ref->new_sha1));\n \n-\t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg);\n+\t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg, plumbing);\n \t}\n }\n \n-static int print_one_push_status(struct ref *ref, const char *dest, int count)\n+static int print_one_push_status(struct ref *ref, const char *dest, int count, int plumbing)\n {\n \tif (!count)\n \t\tfprintf(stderr, \"To %s\\n\", dest);\n \n \tswitch(ref->status) {\n \tcase REF_STATUS_NONE:\n-\t\tprint_ref_status('X', \"[no match]\", ref, NULL, NULL);\n+\t\tprint_ref_status('X', \"[no match]\", ref, NULL, NULL, plumbing);\n \t\tbreak;\n \tcase REF_STATUS_REJECT_NODELETE:\n \t\tprint_ref_status('!', \"[rejected]\", ref, NULL,\n-\t\t\t\t\"remote does not support deleting refs\");\n+\t\t\t\t\t\t \"remote does not support deleting refs\", plumbing);\n \t\tbreak;\n \tcase REF_STATUS_UPTODATE:\n \t\tprint_ref_status('=', \"[up to date]\", ref,\n-\t\t\t\tref->peer_ref, NULL);\n+\t\t\t\t\t\t ref->peer_ref, NULL, plumbing);\n \t\tbreak;\n \tcase REF_STATUS_REJECT_NONFASTFORWARD:\n \t\tprint_ref_status('!', \"[rejected]\", ref, ref->peer_ref,\n-\t\t\t\t\"non-fast forward\");\n+\t\t\t\t\t\t \"non-fast forward\", plumbing);\n \t\tbreak;\n \tcase REF_STATUS_REMOTE_REJECT:\n \t\tprint_ref_status('!', \"[remote rejected]\", ref,\n-\t\t\t\tref->deletion ? NULL : ref->peer_ref,\n-\t\t\t\tref->remote_status);\n+\t\t\t\t\t\t ref->deletion ? NULL : ref->peer_ref,\n+\t\t\t\t\t\t ref->remote_status, plumbing);\n \t\tbreak;\n \tcase REF_STATUS_EXPECTING_REPORT:\n \t\tprint_ref_status('!', \"[remote failure]\", ref,\n-\t\t\t\tref->deletion ? NULL : ref->peer_ref,\n-\t\t\t\t\"remote failed to report status\");\n+\t\t\t\t\t\t ref->deletion ? NULL : ref->peer_ref,\n+\t\t\t\t\t\t \"remote failed to report status\", plumbing);\n \t\tbreak;\n \tcase REF_STATUS_OK:\n-\t\tprint_ok_ref_status(ref);\n+\t\tprint_ok_ref_status(ref, plumbing);\n \t\tbreak;\n \t}\n \n \treturn 1;\n }\n \n-static void print_push_status(const char *dest, struct ref *refs, int verbose)\n+static void print_push_status(const char *dest, struct ref *refs,\n+\t\t\t\t\t\t\t  int verbose, int plumbing)\n {\n \tstruct ref *ref;\n \tint n = 0;\n@@ -816,18 +828,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)\n \tif (verbose) {\n \t\tfor (ref = refs; ref; ref = ref->next)\n \t\t\tif (ref->status == REF_STATUS_UPTODATE)\n-\t\t\t\tn += print_one_push_status(ref, dest, n);\n+\t\t\t\tn += print_one_push_status(ref, dest, n, plumbing);\n \t}\n \n \tfor (ref = refs; ref; ref = ref->next)\n \t\tif (ref->status == REF_STATUS_OK)\n-\t\t\tn += print_one_push_status(ref, dest, n);\n+\t\t\tn += print_one_push_status(ref, dest, n, plumbing);\n \n \tfor (ref = refs; ref; ref = ref->next) {\n \t\tif (ref->status != REF_STATUS_NONE &&\n \t\t    ref->status != REF_STATUS_UPTODATE &&\n \t\t    ref->status != REF_STATUS_OK)\n-\t\t\tn += print_one_push_status(ref, dest, n);\n+\t\t\tn += print_one_push_status(ref, dest, n, plumbing);\n \t}\n }\n \n@@ -997,6 +1009,7 @@ int transport_push(struct transport *transport,\n \t\tstruct ref *local_refs = get_local_heads();\n \t\tint match_flags = MATCH_REFS_NONE;\n \t\tint verbose = flags & TRANSPORT_PUSH_VERBOSE;\n+\t\tint plumbing = flags & TRANSPORT_PUSH_PLUMBING;\n \t\tint ret;\n \n \t\tif (flags & TRANSPORT_PUSH_ALL)\n@@ -1011,7 +1024,7 @@ int transport_push(struct transport *transport,\n \n \t\tret = transport->push_refs(transport, remote_refs, flags);\n \n-\t\tprint_push_status(transport->url, remote_refs, verbose);\n+\t\tprint_push_status(transport->url, remote_refs, verbose | plumbing, plumbing);\n \n \t\tif (!(flags & TRANSPORT_PUSH_DRY_RUN)) {\n \t\t\tstruct ref *ref;\ndiff --git a/transport.h b/transport.h\nindex 27bfc52..f1d8378 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -35,6 +35,7 @@ struct transport {\n #define TRANSPORT_PUSH_DRY_RUN 4\n #define TRANSPORT_PUSH_MIRROR 8\n #define TRANSPORT_PUSH_VERBOSE 16\n+#define TRANSPORT_PUSH_PLUMBING 32\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n-- \n1.6.0.4\n"},{"id":"116824","messageId":"7v4ou79cga.fsf@alter.siamese.dyndns.org","threadId":"19856","inReplyTo":"4A40EF9C.7000706@xiplink.com","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-06-23T15:50:13Z","receivedAt":"2009-06-23T15:50:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Marc Branchaud <marcnarc@xiplink.com> writes:\n\n> Shouldn't this option be named \"--plumbing\" since it's making 'git push'\n> act like plumbing?  Actually, neither name seems intuitively descriptive\n> to me...\n\nPerhaps.  But asking for output format designed for Porcelain\nimplementions to read with --porcelain option has precedence.\n\n> Why not teach 'git push' to change its output format if it's writing to a pipe?\n\nThat is ugly.  Besides, \"writing to a pipe\" would not be a right criteria,\nif you want to do\n\n          git push >log\n          if grep blah log\n          then\n                do blah thing\n          fi\n          if grep baa log\n          then\n                do baa thing, too\n          fi\n\nWhen you make a program behave differently depending on where your stdout\ngoes, typically you see if it is going to the terminal (e.g. isatty(3)),\nbut even then you would need an explicit override from the command line\nwhen stdout is a tty and you do not want \"for humans\" frills (e.g. color),\nand when stdout is not a tty and you do want such frills.\n"},{"id":"116829","messageId":"4A410C64.9030903@xiplink.com","threadId":"19856","inReplyTo":"7v4ou79cga.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2009-06-23T17:09:56Z","receivedAt":"2009-06-23T17:09:56Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"Both good points.  --porcelain is fine by me.\n\n\t\tM.\n\n\nJunio C Hamano wrote:\n> Marc Branchaud <marcnarc@xiplink.com> writes:\n> \n>> Shouldn't this option be named \"--plumbing\" since it's making 'git push'\n>> act like plumbing?  Actually, neither name seems intuitively descriptive\n>> to me...\n> \n> Perhaps.  But asking for output format designed for Porcelain\n> implementions to read with --porcelain option has precedence.\n> \n>> Why not teach 'git push' to change its output format if it's writing to a pipe?\n> \n> That is ugly.  Besides, \"writing to a pipe\" would not be a right criteria,\n> if you want to do\n> \n>           git push >log\n>           if grep blah log\n>           then\n>                 do blah thing\n>           fi\n>           if grep baa log\n>           then\n>                 do baa thing, too\n>           fi\n> \n> When you make a program behave differently depending on where your stdout\n> goes, typically you see if it is going to the terminal (e.g. isatty(3)),\n> but even then you would need an explicit override from the command line\n> when stdout is a tty and you do not want \"for humans\" frills (e.g. color),\n> and when stdout is not a tty and you do want such frills.\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"116833","messageId":"200906232041.25102.markus.heidelberg@web.de","threadId":"19856","inReplyTo":"4A40EF9C.7000706@xiplink.com","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Markus Heidelberg","fromEmail":"markus.heidelberg@web.de","sentAt":"2009-06-23T18:41:24Z","receivedAt":"2009-06-23T18:41:24Z","isPatch":true,"sender":{"key":"markus.heidelberg@web.de","avatar":"https://avatars.githubusercontent.com/u/6334512?v=4"},"body":"Marc Branchaud, 23.06.2009:\n> Shouldn't this option be named \"--plumbing\" since it's making 'git\n> push' act like plumbing?\n\ngit-blame already has --porcelain\n"},{"id":"116838","messageId":"85647ef50906231538m118120adnd2292b65ec953baa@mail.gmail.com","threadId":"19856","inReplyTo":"20090623011001.GA15352@cthulhu","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Constantine Plotnikov","fromEmail":"constantine.plotnikov@gmail.com","sentAt":"2009-06-23T22:38:24Z","receivedAt":"2009-06-23T22:38:24Z","isPatch":true,"sender":{"key":"constantine.plotnikov@gmail.com","avatar":null},"body":"On Tue, Jun 23, 2009 at 5:10 AM, Larry D'Anna<larry@elder-gods.org> wrote:\n> If --porcelain is used git-push will produce machine-readable output.  The\n> output status line for each ref will be tab-separated and sent to stdout instead\n> of stderr.  The full symbolic names of the refs will be given.  For example\n>\nBTW is it possible to have --porcelain + -v together. A machine\nreadable progress output would come very handy for IDEs and other GUI\ntools that use command line tools.\n\nThe git tendency to be less verbose when there is no tty is really\nannoying from point of view of GUI.\n\nRegards,\nConstantine\n"},{"id":"116842","messageId":"20090624002651.GA27460@cthulhu","threadId":"19856","inReplyTo":"85647ef50906231538m118120adnd2292b65ec953baa@mail.gmail.com","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Larry D'Anna","fromEmail":"larry@elder-gods.org","sentAt":"2009-06-24T00:26:51Z","receivedAt":"2009-06-24T00:26:51Z","isPatch":true,"sender":{"key":"larry@elder-gods.org","avatar":"https://avatars.githubusercontent.com/u/3013304?v=4"},"body":"* Constantine Plotnikov (constantine.plotnikov@gmail.com) [090623 18:38]:\n> On Tue, Jun 23, 2009 at 5:10 AM, Larry D'Anna<larry@elder-gods.org> wrote:\n> > If --porcelain is used git-push will produce machine-readable output.  The\n> > output status line for each ref will be tab-separated and sent to stdout instead\n> > of stderr.  The full symbolic names of the refs will be given.  For example\n> >\n> BTW is it possible to have --porcelain + -v together. A machine\n> readable progress output would come very handy for IDEs and other GUI\n> tools that use command line tools.\n\nMy patch makes --porcelain imply some of what -v does, but not all.\nSpecifically --porcelain will output a status line for each ref that's to be\nupdated, weather -v is selected or not.  However -v enables some other output\nbesides that.  There's nothing stopping you from selecting -v and --porcelain.\nBasically --porcelain only affects the per-ref status lines.  All other aspects\nof git-push are the same.\n\n\n        --larry\n"},{"id":"116959","messageId":"7vtz249lpf.fsf@alter.siamese.dyndns.org","threadId":"19856","inReplyTo":"20090623011001.GA15352@cthulhu","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-06-25T19:07:08Z","receivedAt":"2009-06-25T19:07:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Larry D'Anna <larry@elder-gods.org> writes:\n\n> If --porcelain is used git-push will produce machine-readable output.  The\n> output status line for each ref will be tab-separated and sent to stdout instead\n> of stderr.  The full symbolic names of the refs will be given.  For example\n>\n> $ git push --dry-run --porcelain master :foobar 2>/dev/null \\\n>   | perl -pe 's/\\t/ TAB /g'\n>\n> = TAB refs/heads/master:refs/heads/master TAB [up to date]\n> - TAB :refs/heads/foobar TAB [deleted]\n> ---\n\nThanks.  Sign-off?\n\nOn a tangent, this reminds me of something that I often find myself\nwanting to do.  Currently I do:\n\n\t$ git push --dry-run\n           A..B master -> master\n        $ git log --oneline A..B ;# cut and paste A..B from the output\n\t$ git push\n\nto achieve what I want; get an overview of what I'd be pushing as the\nfinal sanity check before running the actual push.\n\nI've been wondering if it would be a good idea to teach -v (or some other\noption) to do this automatically.  That is,\n\n\t$ git push [--dry-run] [--summary[=<n>]]\n\nwould give the output from \"git log --oneline [-n <n>] A..B\".\n\nNo, I am not suggesting you to fold such an unrelated feature to your\npatch at all.\n"},{"id":"116961","messageId":"4A43D049.3030903@elder-gods.org","threadId":"19856","inReplyTo":"7vtz249lpf.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] add --porcelain option to git-push","fromName":"Larry D'Anna","fromEmail":"larry@elder-gods.org","sentAt":"2009-06-25T19:30:17Z","receivedAt":"2009-06-25T19:30:17Z","isPatch":true,"sender":{"key":"larry@elder-gods.org","avatar":"https://avatars.githubusercontent.com/u/3013304?v=4"},"body":"Junio C Hamano wrote:\n> Larry D'Anna <larry@elder-gods.org> writes:\n>\n>   \n>> If --porcelain is used git-push will produce machine-readable output.  The\n>> output status line for each ref will be tab-separated and sent to stdout instead\n>> of stderr.  The full symbolic names of the refs will be given.  For example\n>>\n>> $ git push --dry-run --porcelain master :foobar 2>/dev/null \\\n>>   | perl -pe 's/\\t/ TAB /g'\n>>\n>> = TAB refs/heads/master:refs/heads/master TAB [up to date]\n>> - TAB :refs/heads/foobar TAB [deleted]\n>> ---\n>>     \n>\n> Thanks.  Sign-off?\n>\n>   \nOops.  Yes, I sign-off on this patch.\n\n    --larry\n"},{"id":"117063","messageId":"1246062197-28685-1-git-send-email-larry@elder-gods.org","threadId":"19856","inReplyTo":"7vtz249lpf.fsf@alter.siamese.dyndns.org","subject":"[PATCH] add --summary option to git-push","fromName":"Larry D'Anna","fromEmail":"larry@elder-gods.org","sentAt":"2009-06-27T00:23:17Z","receivedAt":"2009-06-27T00:23:17Z","isPatch":true,"sender":{"key":"larry@elder-gods.org","avatar":"https://avatars.githubusercontent.com/u/3013304?v=4"},"body":"--summary will cause git-push to output a one-line of each commit pushed.\n--summary=n will display at most n commits for each ref pushed.\n\n$ git push --dry-run --summary origin :\nTo /home/larry/gitsandbox/a\n   80f0e50..5593a38  master -> master\n    5593a38 foo\n    81c03f8 bar\n\nSigned-off-by: Larry D'Anna <larry@elder-gods.org>\n---\n Documentation/git-push.txt |    6 ++++++\n builtin-push.c             |   12 +++++++++---\n transport.c                |   43 +++++++++++++++++++++++++++++++------------\n transport.h                |    2 +-\n 4 files changed, 47 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 2653388..803fe36 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -85,6 +85,12 @@ nor in any Push line of the corresponding remotes file---see below).\n --dry-run::\n \tDo everything except actually send the updates.\n \n+--summary::\n+\tPrint a one-line summary of each commit pushed.\n+\n+--summary=<n>::\n+\tLike --summary, but with a limit of <n> commits per ref.\n+\n --porcelain::\n \tProduce machine-readable output.  The output status line for each ref\n \twill be tab-separated and sent to stdout instead of stderr.  The full\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 0a0297f..00cf846 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -113,7 +113,7 @@ static void setup_default_push_refspecs(void)\n \t}\n }\n \n-static int do_push(const char *repo, int flags)\n+static int do_push(const char *repo, int flags, int summary)\n {\n \tint i, errs;\n \tstruct remote *remote = remote_get(repo);\n@@ -173,7 +173,7 @@ static int do_push(const char *repo, int flags)\n \n \t\tif (flags & TRANSPORT_PUSH_VERBOSE)\n \t\t\tfprintf(stderr, \"Pushing to %s\\n\", url[i]);\n-\t\terr = transport_push(transport, refspec_nr, refspec, flags);\n+\t\terr = transport_push(transport, refspec_nr, refspec, flags, summary);\n \t\terr |= transport_disconnect(transport);\n \n \t\tif (!err)\n@@ -192,6 +192,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \tint rc;\n \tconst char *repo = NULL;\t/* default repository */\n \n+\tint summary = 0;\n+\n \tstruct option options[] = {\n \t\tOPT_BIT('v', \"verbose\", &flags, \"be verbose\", TRANSPORT_PUSH_VERBOSE),\n \t\tOPT_STRING( 0 , \"repo\", &repo, \"repository\", \"repository\"),\n@@ -205,6 +207,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOLEAN( 0 , \"thin\", &thin, \"use thin pack\"),\n \t\tOPT_STRING( 0 , \"receive-pack\", &receivepack, \"receive-pack\", \"receive pack program\"),\n \t\tOPT_STRING( 0 , \"exec\", &receivepack, \"receive-pack\", \"receive pack program\"),\n+\t\t{ OPTION_INTEGER, 0, \"summary\", &summary, \"n\", \"print a summary of [at most n] pushed commits\",\n+\t\t  PARSE_OPT_OPTARG, NULL, -1\n+\t\t},\n+\n \t\tOPT_END()\n \t};\n \n@@ -218,7 +224,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tset_refspecs(argv + 1, argc - 1);\n \t}\n \n-\trc = do_push(repo, flags);\n+\trc = do_push(repo, flags, summary);\n \tif (rc == -1)\n \t\tusage_with_options(push_usage, options);\n \telse\ndiff --git a/transport.c b/transport.c\nindex b074067..562e788 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -750,17 +750,19 @@ static const char *status_abbrev(unsigned char sha1[20])\n \treturn find_unique_abbrev(sha1, DEFAULT_ABBREV);\n }\n \n-static void print_ok_ref_status(struct ref *ref, int porcelain)\n+static void print_ok_ref_status(struct ref *ref, int porcelain, int summary)\n {\n+\tchar quickref[84];\n+\n \tif (ref->deletion)\n \t\tprint_ref_status('-', \"[deleted]\", ref, NULL, NULL, porcelain);\n-\telse if (is_null_sha1(ref->old_sha1))\n+\telse if (is_null_sha1(ref->old_sha1)) {\n \t\tprint_ref_status('*',\n \t\t\t(!prefixcmp(ref->name, \"refs/tags/\") ? \"[new tag]\" :\n \t\t\t\"[new branch]\"),\n \t\t\tref, ref->peer_ref, NULL, porcelain);\n-\telse {\n-\t\tchar quickref[84];\n+\t\tstrcpy (quickref, status_abbrev(ref->new_sha1));\n+\t} else {\n \t\tchar type;\n \t\tconst char *msg;\n \n@@ -778,9 +780,25 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)\n \n \t\tprint_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);\n \t}\n+\n+\tif (summary) {\n+\t\tFILE *temp = stdout;\n+\t\tstdout = stderr;\n+\t\tif (summary < 0) {\n+\t\t\tchar *argv[] = {\"log\", \"--pretty=format:    %h %s\", quickref};\n+\t\t\tcmd_log(3, argv, 0);\n+\t\t} else {\n+\t\t\tchar dashn[15];\n+\t\t\tsprintf(dashn, \"-n%d\", summary);\n+\t\t\tchar *argv[] = {\"log\", \"--pretty=format:    %h %s\", dashn, quickref};\n+\t\t\tcmd_log(4, argv, 0);\n+\t\t}\n+\t\tfprintf(stderr, \"\\n\");\n+\t\tstdout = temp;\n+\t}\n }\n \n-static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)\n+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain, int summary)\n {\n \tif (!count)\n \t\tfprintf(stderr, \"To %s\\n\", dest);\n@@ -812,7 +830,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i\n \t\t\t\t\t\t \"remote failed to report status\", porcelain);\n \t\tbreak;\n \tcase REF_STATUS_OK:\n-\t\tprint_ok_ref_status(ref, porcelain);\n+\t\tprint_ok_ref_status(ref, porcelain, summary);\n \t\tbreak;\n \t}\n \n@@ -820,7 +838,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i\n }\n \n static void print_push_status(const char *dest, struct ref *refs,\n-\t\t\t\t\t\t\t  int verbose, int porcelain)\n+\t\t\t\t\t\t\t  int verbose, int porcelain, int summary)\n {\n \tstruct ref *ref;\n \tint n = 0;\n@@ -828,18 +846,18 @@ static void print_push_status(const char *dest, struct ref *refs,\n \tif (verbose) {\n \t\tfor (ref = refs; ref; ref = ref->next)\n \t\t\tif (ref->status == REF_STATUS_UPTODATE)\n-\t\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n+\t\t\t\tn += print_one_push_status(ref, dest, n, porcelain, summary);\n \t}\n \n \tfor (ref = refs; ref; ref = ref->next)\n \t\tif (ref->status == REF_STATUS_OK)\n-\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n+\t\t\tn += print_one_push_status(ref, dest, n, porcelain, summary);\n \n \tfor (ref = refs; ref; ref = ref->next) {\n \t\tif (ref->status != REF_STATUS_NONE &&\n \t\t    ref->status != REF_STATUS_UPTODATE &&\n \t\t    ref->status != REF_STATUS_OK)\n-\t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n+\t\t\tn += print_one_push_status(ref, dest, n, porcelain, summary);\n \t}\n }\n \n@@ -997,7 +1015,8 @@ int transport_set_option(struct transport *transport,\n }\n \n int transport_push(struct transport *transport,\n-\t\t   int refspec_nr, const char **refspec, int flags)\n+\t\t\t\t   int refspec_nr, const char **refspec,\n+\t\t\t\t   int flags, int summary)\n {\n \tverify_remote_names(refspec_nr, refspec);\n \n@@ -1024,7 +1043,7 @@ int transport_push(struct transport *transport,\n \n \t\tret = transport->push_refs(transport, remote_refs, flags);\n \n-\t\tprint_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);\n+\t\tprint_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, summary);\n \n \t\tif (!(flags & TRANSPORT_PUSH_DRY_RUN)) {\n \t\t\tstruct ref *ref;\ndiff --git a/transport.h b/transport.h\nindex 51b5397..360051e 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -68,7 +68,7 @@ int transport_set_option(struct transport *transport, const char *name,\n \t\t\t const char *value);\n \n int transport_push(struct transport *connection,\n-\t\t   int refspec_nr, const char **refspec, int flags);\n+\t\t\t\t   int refspec_nr, const char **refspec, int flags, int summary);\n \n const struct ref *transport_get_remote_refs(struct transport *transport);\n \n-- \n1.6.0.4\n"}]}