git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* I'd like to be able to know what git-push will do
@ 2009-06-18 21:28 Larry D'Anna
  2009-06-22 21:40 ` Jeff King
  0 siblings, 1 reply; 13+ messages in thread
From: Larry D'Anna @ 2009-06-18 21:28 UTC (permalink / raw)
  To: git

I previously sent this to Junio, but I think I should have just sent it to the
list.

I'd like to be able to call git-push --dry-run and process the result from a
perl script, but there's a snag: what does "foobar -> foobar" mean?  foobar
could be a tag or a branch.  In fact, it could be a branch on on side and a tag
on the other!  

I've tried duplicating the refspec processing in the perl script, but this
approach is highly sub-optimal because the refspec parsing and matching is so
complicated.  I would wind up duplicating a lot of functionality, and every time
it changed in git my script would become broken.

Would you accept a patch that changes the behavior of git-push so that instead of

  $ git-push --dry-run  -v origin :
  Pushing to ~/repos/bin
  To ~/repos/bin
   = [up to date]      master -> master
  Everything up-to-date
  
It would print the full names like this (only if -v is used)

  $ git-push --dry-run  -v origin :
  Pushing to ~/repos/bin
  To ~/repos/bin
   = [up to date]      refs/heads/master -> refs/heads/master
  Everything up-to-date

Or, if you don't like changing the behavior of -v, would you accept a patch with
a new option (perhaps --symbolic-full-name) that caused git-push to behave this
way?

Once I know what the user interface should be (-v or --symbolic-full-name or
whatever) I'll post a patch.

Thanks!

        --larry

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: I'd like to be able to know what git-push will do
  2009-06-18 21:28 I'd like to be able to know what git-push will do Larry D'Anna
@ 2009-06-22 21:40 ` Jeff King
  2009-06-23  1:10   ` [PATCH] add --porcelain option to git-push Larry D'Anna
  0 siblings, 1 reply; 13+ messages in thread
From: Jeff King @ 2009-06-22 21:40 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git

On Thu, Jun 18, 2009 at 05:28:03PM -0400, Larry D'Anna wrote:

> I'd like to be able to call git-push --dry-run and process the result
> from a perl script, but there's a snag: what does "foobar -> foobar"
> mean?  foobar could be a tag or a branch.  In fact, it could be a
> branch on on side and a tag on the other!

Yeah, that output is really meant for human consumption.

> I've tried duplicating the refspec processing in the perl script, but
> this approach is highly sub-optimal because the refspec parsing and
> matching is so complicated.  I would wind up duplicating a lot of
> functionality, and every time it changed in git my script would become
> broken.

Agreed.

> Would you accept a patch that changes the behavior of git-push so that
> instead of
> 
>   $ git-push --dry-run  -v origin :
>   Pushing to ~/repos/bin
>   To ~/repos/bin
>    = [up to date]      master -> master
>   Everything up-to-date
>   
> It would print the full names like this (only if -v is used)
> 
>   $ git-push --dry-run  -v origin :
>   Pushing to ~/repos/bin
>   To ~/repos/bin
>    = [up to date]      refs/heads/master -> refs/heads/master
>   Everything up-to-date
> 
> Or, if you don't like changing the behavior of -v, would you accept a
> patch with a new option (perhaps --symbolic-full-name) that caused
> git-push to behave this way?

I think it would have to be a new option, as "-v" is really about
something orthogonal. However, I actually think you are better off
making a whole new output format for porcelain scripts to read. As I
said, the current output is for human consumption, and I wouldn't rule
out the possibility of it changing in the future (and it won't receive
the same sort of deprecation treatment that an interface created for
scripts would get).

In other words, something like:

  $ git push --dry-run --porcelain origin :
  =refs/heads/master:refs/heads/master

(the format is totally off the top of my head -- I haven't thought too
long about what you might want to have in it).

-Peff

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] add --porcelain option to git-push
  2009-06-22 21:40 ` Jeff King
@ 2009-06-23  1:10   ` Larry D'Anna
  2009-06-23 15:07     ` Marc Branchaud
                       ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Larry D'Anna @ 2009-06-23  1:10 UTC (permalink / raw)
  To: git

If --porcelain is used git-push will produce machine-readable output.  The
output status line for each ref will be tab-separated and sent to stdout instead
of stderr.  The full symbolic names of the refs will be given.  For example

$ git push --dry-run --porcelain master :foobar 2>/dev/null \
  | perl -pe 's/\t/ TAB /g'

= TAB refs/heads/master:refs/heads/master TAB [up to date]
- TAB :refs/heads/foobar TAB [deleted]
---
 Documentation/git-push.txt |   11 ++++++
 builtin-push.c             |    3 +-
 transport.c                |   75 +++++++++++++++++++++++++------------------
 transport.h                |    1 +
 4 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index fd53c49..2653388 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).
 --dry-run::
 	Do everything except actually send the updates.
 
+--porcelain::
+	Produce machine-readable output.  The output status line for each ref
+	will be tab-separated and sent to stdout instead of stderr.  The full
+	symbolic names of the refs will be given.
+
 --tags::
 	All refs under `$GIT_DIR/refs/tags` are pushed, in
 	addition to refspecs explicitly listed on the command
@@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:
  <flag> <summary> <from> -> <to> (<reason>)
 -------------------------------
 
+If --porcelain is used, then each line of the output is of the form:
+
+-------------------------------
+ <flag> \t <from>:<to> \t <summary> (<reason>)
+-------------------------------
+
 flag::
 	A single character indicating the status of the ref. This is
 	blank for a successfully pushed ref, `!` for a ref that was
diff --git a/builtin-push.c b/builtin-push.c
index 7be1239..0a0297f 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-	"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
+	"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
 	NULL,
 };
 
@@ -200,6 +200,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 			    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
 		OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
+		OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
 		OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
diff --git a/transport.c b/transport.c
index 501a77b..b074067 100644
--- a/transport.c
+++ b/transport.c
@@ -719,19 +719,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb
 
 #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
 
-static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
 {
-	fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
-	if (from)
-		fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
-	else
-		fputs(prettify_refname(to->name), stderr);
-	if (msg) {
-		fputs(" (", stderr);
-		fputs(msg, stderr);
-		fputc(')', stderr);
+	if (porcelain) {
+		if (from)
+			fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+		else
+			fprintf(stdout, "%c\t:%s\t", flag, to->name);
+		if (msg)
+			fprintf(stdout, "%s (%s)\n", summary, msg);
+		else
+			fprintf(stdout, "%s\n", summary);
+	} else {
+		fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
+		if (from)
+			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
+		else
+			fputs(prettify_refname(to->name), stderr);
+		if (msg) {
+			fputs(" (", stderr);
+			fputs(msg, stderr);
+			fputc(')', stderr);
+		}
+		fputc('\n', stderr);
 	}
-	fputc('\n', stderr);
 }
 
 static const char *status_abbrev(unsigned char sha1[20])
@@ -739,15 +750,15 @@ static const char *status_abbrev(unsigned char sha1[20])
 	return find_unique_abbrev(sha1, DEFAULT_ABBREV);
 }
 
-static void print_ok_ref_status(struct ref *ref)
+static void print_ok_ref_status(struct ref *ref, int porcelain)
 {
 	if (ref->deletion)
-		print_ref_status('-', "[deleted]", ref, NULL, NULL);
+		print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
 	else if (is_null_sha1(ref->old_sha1))
 		print_ref_status('*',
 			(!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
-			  "[new branch]"),
-			ref, ref->peer_ref, NULL);
+			"[new branch]"),
+			ref, ref->peer_ref, NULL, porcelain);
 	else {
 		char quickref[84];
 		char type;
@@ -765,50 +776,51 @@ static void print_ok_ref_status(struct ref *ref)
 		}
 		strcat(quickref, status_abbrev(ref->new_sha1));
 
-		print_ref_status(type, quickref, ref, ref->peer_ref, msg);
+		print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
 	}
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
 {
 	if (!count)
 		fprintf(stderr, "To %s\n", dest);
 
 	switch(ref->status) {
 	case REF_STATUS_NONE:
-		print_ref_status('X', "[no match]", ref, NULL, NULL);
+		print_ref_status('X', "[no match]", ref, NULL, NULL, porcelain);
 		break;
 	case REF_STATUS_REJECT_NODELETE:
 		print_ref_status('!', "[rejected]", ref, NULL,
-				"remote does not support deleting refs");
+						 "remote does not support deleting refs", porcelain);
 		break;
 	case REF_STATUS_UPTODATE:
 		print_ref_status('=', "[up to date]", ref,
-				ref->peer_ref, NULL);
+						 ref->peer_ref, NULL, porcelain);
 		break;
 	case REF_STATUS_REJECT_NONFASTFORWARD:
 		print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-				"non-fast forward");
+						 "non-fast forward", porcelain);
 		break;
 	case REF_STATUS_REMOTE_REJECT:
 		print_ref_status('!', "[remote rejected]", ref,
-				ref->deletion ? NULL : ref->peer_ref,
-				ref->remote_status);
+						 ref->deletion ? NULL : ref->peer_ref,
+						 ref->remote_status, porcelain);
 		break;
 	case REF_STATUS_EXPECTING_REPORT:
 		print_ref_status('!', "[remote failure]", ref,
-				ref->deletion ? NULL : ref->peer_ref,
-				"remote failed to report status");
+						 ref->deletion ? NULL : ref->peer_ref,
+						 "remote failed to report status", porcelain);
 		break;
 	case REF_STATUS_OK:
-		print_ok_ref_status(ref);
+		print_ok_ref_status(ref, porcelain);
 		break;
 	}
 
 	return 1;
 }
 
-static void print_push_status(const char *dest, struct ref *refs, int verbose)
+static void print_push_status(const char *dest, struct ref *refs,
+							  int verbose, int porcelain)
 {
 	struct ref *ref;
 	int n = 0;
@@ -816,18 +828,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)
 	if (verbose) {
 		for (ref = refs; ref; ref = ref->next)
 			if (ref->status == REF_STATUS_UPTODATE)
-				n += print_one_push_status(ref, dest, n);
+				n += print_one_push_status(ref, dest, n, porcelain);
 	}
 
 	for (ref = refs; ref; ref = ref->next)
 		if (ref->status == REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n);
+			n += print_one_push_status(ref, dest, n, porcelain);
 
 	for (ref = refs; ref; ref = ref->next) {
 		if (ref->status != REF_STATUS_NONE &&
 		    ref->status != REF_STATUS_UPTODATE &&
 		    ref->status != REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n);
+			n += print_one_push_status(ref, dest, n, porcelain);
 	}
 }
 
@@ -997,6 +1009,7 @@ int transport_push(struct transport *transport,
 		struct ref *local_refs = get_local_heads();
 		int match_flags = MATCH_REFS_NONE;
 		int verbose = flags & TRANSPORT_PUSH_VERBOSE;
+		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int ret;
 
 		if (flags & TRANSPORT_PUSH_ALL)
@@ -1011,7 +1024,7 @@ int transport_push(struct transport *transport,
 
 		ret = transport->push_refs(transport, remote_refs, flags);
 
-		print_push_status(transport->url, remote_refs, verbose);
+		print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);
 
 		if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
 			struct ref *ref;
diff --git a/transport.h b/transport.h
index 27bfc52..51b5397 100644
--- a/transport.h
+++ b/transport.h
@@ -35,6 +35,7 @@ struct transport {
 #define TRANSPORT_PUSH_DRY_RUN 4
 #define TRANSPORT_PUSH_MIRROR 8
 #define TRANSPORT_PUSH_VERBOSE 16
+#define TRANSPORT_PUSH_PORCELAIN 32
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23  1:10   ` [PATCH] add --porcelain option to git-push Larry D'Anna
@ 2009-06-23 15:07     ` Marc Branchaud
  2009-06-23 15:38       ` [PATCH] add --plumbing " Larry D'Anna
                         ` (2 more replies)
  2009-06-23 22:38     ` Constantine Plotnikov
  2009-06-25 19:07     ` Junio C Hamano
  2 siblings, 3 replies; 13+ messages in thread
From: Marc Branchaud @ 2009-06-23 15:07 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git

Shouldn't this option be named "--plumbing" since it's making 'git push' act like plumbing?  Actually, neither name seems intuitively descriptive to me...

Why not teach 'git push' to change its output format if it's writing to a pipe?

		M.


Larry D'Anna wrote:
> If --porcelain is used git-push will produce machine-readable output.  The
> output status line for each ref will be tab-separated and sent to stdout instead
> of stderr.  The full symbolic names of the refs will be given.  For example
> 
> $ git push --dry-run --porcelain master :foobar 2>/dev/null \
>   | perl -pe 's/\t/ TAB /g'
> 
> = TAB refs/heads/master:refs/heads/master TAB [up to date]
> - TAB :refs/heads/foobar TAB [deleted]
> ---
>  Documentation/git-push.txt |   11 ++++++
>  builtin-push.c             |    3 +-
>  transport.c                |   75 +++++++++++++++++++++++++------------------
>  transport.h                |    1 +
>  4 files changed, 58 insertions(+), 32 deletions(-)
> 
> diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
> index fd53c49..2653388 100644
> --- a/Documentation/git-push.txt
> +++ b/Documentation/git-push.txt
> @@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).
>  --dry-run::
>  	Do everything except actually send the updates.
>  
> +--porcelain::
> +	Produce machine-readable output.  The output status line for each ref
> +	will be tab-separated and sent to stdout instead of stderr.  The full
> +	symbolic names of the refs will be given.
> +
>  --tags::
>  	All refs under `$GIT_DIR/refs/tags` are pushed, in
>  	addition to refspecs explicitly listed on the command
> @@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:
>   <flag> <summary> <from> -> <to> (<reason>)
>  -------------------------------
>  
> +If --porcelain is used, then each line of the output is of the form:
> +
> +-------------------------------
> + <flag> \t <from>:<to> \t <summary> (<reason>)
> +-------------------------------
> +
>  flag::
>  	A single character indicating the status of the ref. This is
>  	blank for a successfully pushed ref, `!` for a ref that was
> diff --git a/builtin-push.c b/builtin-push.c
> index 7be1239..0a0297f 100644
> --- a/builtin-push.c
> +++ b/builtin-push.c
> @@ -10,7 +10,7 @@
>  #include "parse-options.h"
>  
>  static const char * const push_usage[] = {
> -	"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
> +	"git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
>  	NULL,
>  };
>  
> @@ -200,6 +200,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
>  			    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
>  		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
>  		OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
> +		OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
>  		OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
>  		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
>  		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
> diff --git a/transport.c b/transport.c
> index 501a77b..b074067 100644
> --- a/transport.c
> +++ b/transport.c
> @@ -719,19 +719,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb
>  
>  #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
>  
> -static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
> +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
>  {
> -	fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
> -	if (from)
> -		fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
> -	else
> -		fputs(prettify_refname(to->name), stderr);
> -	if (msg) {
> -		fputs(" (", stderr);
> -		fputs(msg, stderr);
> -		fputc(')', stderr);
> +	if (porcelain) {
> +		if (from)
> +			fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
> +		else
> +			fprintf(stdout, "%c\t:%s\t", flag, to->name);
> +		if (msg)
> +			fprintf(stdout, "%s (%s)\n", summary, msg);
> +		else
> +			fprintf(stdout, "%s\n", summary);
> +	} else {
> +		fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
> +		if (from)
> +			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
> +		else
> +			fputs(prettify_refname(to->name), stderr);
> +		if (msg) {
> +			fputs(" (", stderr);
> +			fputs(msg, stderr);
> +			fputc(')', stderr);
> +		}
> +		fputc('\n', stderr);
>  	}
> -	fputc('\n', stderr);
>  }
>  
>  static const char *status_abbrev(unsigned char sha1[20])
> @@ -739,15 +750,15 @@ static const char *status_abbrev(unsigned char sha1[20])
>  	return find_unique_abbrev(sha1, DEFAULT_ABBREV);
>  }
>  
> -static void print_ok_ref_status(struct ref *ref)
> +static void print_ok_ref_status(struct ref *ref, int porcelain)
>  {
>  	if (ref->deletion)
> -		print_ref_status('-', "[deleted]", ref, NULL, NULL);
> +		print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
>  	else if (is_null_sha1(ref->old_sha1))
>  		print_ref_status('*',
>  			(!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
> -			  "[new branch]"),
> -			ref, ref->peer_ref, NULL);
> +			"[new branch]"),
> +			ref, ref->peer_ref, NULL, porcelain);
>  	else {
>  		char quickref[84];
>  		char type;
> @@ -765,50 +776,51 @@ static void print_ok_ref_status(struct ref *ref)
>  		}
>  		strcat(quickref, status_abbrev(ref->new_sha1));
>  
> -		print_ref_status(type, quickref, ref, ref->peer_ref, msg);
> +		print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
>  	}
>  }
>  
> -static int print_one_push_status(struct ref *ref, const char *dest, int count)
> +static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
>  {
>  	if (!count)
>  		fprintf(stderr, "To %s\n", dest);
>  
>  	switch(ref->status) {
>  	case REF_STATUS_NONE:
> -		print_ref_status('X', "[no match]", ref, NULL, NULL);
> +		print_ref_status('X', "[no match]", ref, NULL, NULL, porcelain);
>  		break;
>  	case REF_STATUS_REJECT_NODELETE:
>  		print_ref_status('!', "[rejected]", ref, NULL,
> -				"remote does not support deleting refs");
> +						 "remote does not support deleting refs", porcelain);
>  		break;
>  	case REF_STATUS_UPTODATE:
>  		print_ref_status('=', "[up to date]", ref,
> -				ref->peer_ref, NULL);
> +						 ref->peer_ref, NULL, porcelain);
>  		break;
>  	case REF_STATUS_REJECT_NONFASTFORWARD:
>  		print_ref_status('!', "[rejected]", ref, ref->peer_ref,
> -				"non-fast forward");
> +						 "non-fast forward", porcelain);
>  		break;
>  	case REF_STATUS_REMOTE_REJECT:
>  		print_ref_status('!', "[remote rejected]", ref,
> -				ref->deletion ? NULL : ref->peer_ref,
> -				ref->remote_status);
> +						 ref->deletion ? NULL : ref->peer_ref,
> +						 ref->remote_status, porcelain);
>  		break;
>  	case REF_STATUS_EXPECTING_REPORT:
>  		print_ref_status('!', "[remote failure]", ref,
> -				ref->deletion ? NULL : ref->peer_ref,
> -				"remote failed to report status");
> +						 ref->deletion ? NULL : ref->peer_ref,
> +						 "remote failed to report status", porcelain);
>  		break;
>  	case REF_STATUS_OK:
> -		print_ok_ref_status(ref);
> +		print_ok_ref_status(ref, porcelain);
>  		break;
>  	}
>  
>  	return 1;
>  }
>  
> -static void print_push_status(const char *dest, struct ref *refs, int verbose)
> +static void print_push_status(const char *dest, struct ref *refs,
> +							  int verbose, int porcelain)
>  {
>  	struct ref *ref;
>  	int n = 0;
> @@ -816,18 +828,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)
>  	if (verbose) {
>  		for (ref = refs; ref; ref = ref->next)
>  			if (ref->status == REF_STATUS_UPTODATE)
> -				n += print_one_push_status(ref, dest, n);
> +				n += print_one_push_status(ref, dest, n, porcelain);
>  	}
>  
>  	for (ref = refs; ref; ref = ref->next)
>  		if (ref->status == REF_STATUS_OK)
> -			n += print_one_push_status(ref, dest, n);
> +			n += print_one_push_status(ref, dest, n, porcelain);
>  
>  	for (ref = refs; ref; ref = ref->next) {
>  		if (ref->status != REF_STATUS_NONE &&
>  		    ref->status != REF_STATUS_UPTODATE &&
>  		    ref->status != REF_STATUS_OK)
> -			n += print_one_push_status(ref, dest, n);
> +			n += print_one_push_status(ref, dest, n, porcelain);
>  	}
>  }
>  
> @@ -997,6 +1009,7 @@ int transport_push(struct transport *transport,
>  		struct ref *local_refs = get_local_heads();
>  		int match_flags = MATCH_REFS_NONE;
>  		int verbose = flags & TRANSPORT_PUSH_VERBOSE;
> +		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
>  		int ret;
>  
>  		if (flags & TRANSPORT_PUSH_ALL)
> @@ -1011,7 +1024,7 @@ int transport_push(struct transport *transport,
>  
>  		ret = transport->push_refs(transport, remote_refs, flags);
>  
> -		print_push_status(transport->url, remote_refs, verbose);
> +		print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);
>  
>  		if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
>  			struct ref *ref;
> diff --git a/transport.h b/transport.h
> index 27bfc52..51b5397 100644
> --- a/transport.h
> +++ b/transport.h
> @@ -35,6 +35,7 @@ struct transport {
>  #define TRANSPORT_PUSH_DRY_RUN 4
>  #define TRANSPORT_PUSH_MIRROR 8
>  #define TRANSPORT_PUSH_VERBOSE 16
> +#define TRANSPORT_PUSH_PORCELAIN 32
>  
>  /* Returns a transport suitable for the url */
>  struct transport *transport_get(struct remote *, const char *);

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] add --plumbing option to git-push
  2009-06-23 15:07     ` Marc Branchaud
@ 2009-06-23 15:38       ` Larry D'Anna
  2009-06-23 15:50       ` [PATCH] add --porcelain " Junio C Hamano
  2009-06-23 18:41       ` Markus Heidelberg
  2 siblings, 0 replies; 13+ messages in thread
From: Larry D'Anna @ 2009-06-23 15:38 UTC (permalink / raw)
  To: git

If --plumbing is used git-push will produce machine-readable output.  The
output status line for each ref will be tab-separated and sent to stdout instead
of stderr.  The full symbolic names of the refs will be given.  For example

$ git push --dry-run --plumbing master :foobar 2>/dev/null \
  | perl -pe 's/\t/ TAB /g'

= TAB refs/heads/master:refs/heads/master TAB [up to date]
- TAB :refs/heads/foobar TAB [deleted]
---
 Documentation/git-push.txt |   11 ++++++
 builtin-push.c             |    3 +-
 transport.c                |   75 +++++++++++++++++++++++++------------------
 transport.h                |    1 +
 4 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index fd53c49..9178145 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -85,6 +85,11 @@ nor in any Push line of the corresponding remotes file---see below).
 --dry-run::
 	Do everything except actually send the updates.
 
+--plumbing::
+	Produce machine-readable output.  The output status line for each ref
+	will be tab-separated and sent to stdout instead of stderr.  The full
+	symbolic names of the refs will be given.
+
 --tags::
 	All refs under `$GIT_DIR/refs/tags` are pushed, in
 	addition to refspecs explicitly listed on the command
@@ -148,6 +153,12 @@ representing the status of a single ref. Each line is of the form:
  <flag> <summary> <from> -> <to> (<reason>)
 -------------------------------
 
+If --plumbing is used, then each line of the output is of the form:
+
+-------------------------------
+ <flag> \t <from>:<to> \t <summary> (<reason>)
+-------------------------------
+
 flag::
 	A single character indicating the status of the ref. This is
 	blank for a successfully pushed ref, `!` for a ref that was
diff --git a/builtin-push.c b/builtin-push.c
index 7be1239..845db1b 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-	"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
+	"git push [--all | --mirror] [--dry-run] [--plumbing] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
 	NULL,
 };
 
@@ -200,6 +200,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 			    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
 		OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
+		OPT_BIT( 0,  "plumbing", &flags, "machine-readable output", TRANSPORT_PUSH_PLUMBING),
 		OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
diff --git a/transport.c b/transport.c
index 501a77b..09d9baa 100644
--- a/transport.c
+++ b/transport.c
@@ -719,19 +719,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb
 
 #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
 
-static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int plumbing)
 {
-	fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
-	if (from)
-		fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
-	else
-		fputs(prettify_refname(to->name), stderr);
-	if (msg) {
-		fputs(" (", stderr);
-		fputs(msg, stderr);
-		fputc(')', stderr);
+	if (plumbing) {
+		if (from)
+			fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+		else
+			fprintf(stdout, "%c\t:%s\t", flag, to->name);
+		if (msg)
+			fprintf(stdout, "%s (%s)\n", summary, msg);
+		else
+			fprintf(stdout, "%s\n", summary);
+	} else {
+		fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
+		if (from)
+			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
+		else
+			fputs(prettify_refname(to->name), stderr);
+		if (msg) {
+			fputs(" (", stderr);
+			fputs(msg, stderr);
+			fputc(')', stderr);
+		}
+		fputc('\n', stderr);
 	}
-	fputc('\n', stderr);
 }
 
 static const char *status_abbrev(unsigned char sha1[20])
@@ -739,15 +750,15 @@ static const char *status_abbrev(unsigned char sha1[20])
 	return find_unique_abbrev(sha1, DEFAULT_ABBREV);
 }
 
-static void print_ok_ref_status(struct ref *ref)
+static void print_ok_ref_status(struct ref *ref, int plumbing)
 {
 	if (ref->deletion)
-		print_ref_status('-', "[deleted]", ref, NULL, NULL);
+		print_ref_status('-', "[deleted]", ref, NULL, NULL, plumbing);
 	else if (is_null_sha1(ref->old_sha1))
 		print_ref_status('*',
 			(!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
-			  "[new branch]"),
-			ref, ref->peer_ref, NULL);
+			"[new branch]"),
+			ref, ref->peer_ref, NULL, plumbing);
 	else {
 		char quickref[84];
 		char type;
@@ -765,50 +776,51 @@ static void print_ok_ref_status(struct ref *ref)
 		}
 		strcat(quickref, status_abbrev(ref->new_sha1));
 
-		print_ref_status(type, quickref, ref, ref->peer_ref, msg);
+		print_ref_status(type, quickref, ref, ref->peer_ref, msg, plumbing);
 	}
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int plumbing)
 {
 	if (!count)
 		fprintf(stderr, "To %s\n", dest);
 
 	switch(ref->status) {
 	case REF_STATUS_NONE:
-		print_ref_status('X', "[no match]", ref, NULL, NULL);
+		print_ref_status('X', "[no match]", ref, NULL, NULL, plumbing);
 		break;
 	case REF_STATUS_REJECT_NODELETE:
 		print_ref_status('!', "[rejected]", ref, NULL,
-				"remote does not support deleting refs");
+						 "remote does not support deleting refs", plumbing);
 		break;
 	case REF_STATUS_UPTODATE:
 		print_ref_status('=', "[up to date]", ref,
-				ref->peer_ref, NULL);
+						 ref->peer_ref, NULL, plumbing);
 		break;
 	case REF_STATUS_REJECT_NONFASTFORWARD:
 		print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-				"non-fast forward");
+						 "non-fast forward", plumbing);
 		break;
 	case REF_STATUS_REMOTE_REJECT:
 		print_ref_status('!', "[remote rejected]", ref,
-				ref->deletion ? NULL : ref->peer_ref,
-				ref->remote_status);
+						 ref->deletion ? NULL : ref->peer_ref,
+						 ref->remote_status, plumbing);
 		break;
 	case REF_STATUS_EXPECTING_REPORT:
 		print_ref_status('!', "[remote failure]", ref,
-				ref->deletion ? NULL : ref->peer_ref,
-				"remote failed to report status");
+						 ref->deletion ? NULL : ref->peer_ref,
+						 "remote failed to report status", plumbing);
 		break;
 	case REF_STATUS_OK:
-		print_ok_ref_status(ref);
+		print_ok_ref_status(ref, plumbing);
 		break;
 	}
 
 	return 1;
 }
 
-static void print_push_status(const char *dest, struct ref *refs, int verbose)
+static void print_push_status(const char *dest, struct ref *refs,
+							  int verbose, int plumbing)
 {
 	struct ref *ref;
 	int n = 0;
@@ -816,18 +828,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)
 	if (verbose) {
 		for (ref = refs; ref; ref = ref->next)
 			if (ref->status == REF_STATUS_UPTODATE)
-				n += print_one_push_status(ref, dest, n);
+				n += print_one_push_status(ref, dest, n, plumbing);
 	}
 
 	for (ref = refs; ref; ref = ref->next)
 		if (ref->status == REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n);
+			n += print_one_push_status(ref, dest, n, plumbing);
 
 	for (ref = refs; ref; ref = ref->next) {
 		if (ref->status != REF_STATUS_NONE &&
 		    ref->status != REF_STATUS_UPTODATE &&
 		    ref->status != REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n);
+			n += print_one_push_status(ref, dest, n, plumbing);
 	}
 }
 
@@ -997,6 +1009,7 @@ int transport_push(struct transport *transport,
 		struct ref *local_refs = get_local_heads();
 		int match_flags = MATCH_REFS_NONE;
 		int verbose = flags & TRANSPORT_PUSH_VERBOSE;
+		int plumbing = flags & TRANSPORT_PUSH_PLUMBING;
 		int ret;
 
 		if (flags & TRANSPORT_PUSH_ALL)
@@ -1011,7 +1024,7 @@ int transport_push(struct transport *transport,
 
 		ret = transport->push_refs(transport, remote_refs, flags);
 
-		print_push_status(transport->url, remote_refs, verbose);
+		print_push_status(transport->url, remote_refs, verbose | plumbing, plumbing);
 
 		if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
 			struct ref *ref;
diff --git a/transport.h b/transport.h
index 27bfc52..f1d8378 100644
--- a/transport.h
+++ b/transport.h
@@ -35,6 +35,7 @@ struct transport {
 #define TRANSPORT_PUSH_DRY_RUN 4
 #define TRANSPORT_PUSH_MIRROR 8
 #define TRANSPORT_PUSH_VERBOSE 16
+#define TRANSPORT_PUSH_PLUMBING 32
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23 15:07     ` Marc Branchaud
  2009-06-23 15:38       ` [PATCH] add --plumbing " Larry D'Anna
@ 2009-06-23 15:50       ` Junio C Hamano
  2009-06-23 17:09         ` Marc Branchaud
  2009-06-23 18:41       ` Markus Heidelberg
  2 siblings, 1 reply; 13+ messages in thread
From: Junio C Hamano @ 2009-06-23 15:50 UTC (permalink / raw)
  To: Marc Branchaud; +Cc: Larry D'Anna, git

Marc Branchaud <marcnarc@xiplink.com> writes:

> Shouldn't this option be named "--plumbing" since it's making 'git push'
> act like plumbing?  Actually, neither name seems intuitively descriptive
> to me...

Perhaps.  But asking for output format designed for Porcelain
implementions to read with --porcelain option has precedence.

> Why not teach 'git push' to change its output format if it's writing to a pipe?

That is ugly.  Besides, "writing to a pipe" would not be a right criteria,
if you want to do

          git push >log
          if grep blah log
          then
                do blah thing
          fi
          if grep baa log
          then
                do baa thing, too
          fi

When you make a program behave differently depending on where your stdout
goes, typically you see if it is going to the terminal (e.g. isatty(3)),
but even then you would need an explicit override from the command line
when stdout is a tty and you do not want "for humans" frills (e.g. color),
and when stdout is not a tty and you do want such frills.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23 15:50       ` [PATCH] add --porcelain " Junio C Hamano
@ 2009-06-23 17:09         ` Marc Branchaud
  0 siblings, 0 replies; 13+ messages in thread
From: Marc Branchaud @ 2009-06-23 17:09 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Larry D'Anna, git

Both good points.  --porcelain is fine by me.

		M.


Junio C Hamano wrote:
> Marc Branchaud <marcnarc@xiplink.com> writes:
> 
>> Shouldn't this option be named "--plumbing" since it's making 'git push'
>> act like plumbing?  Actually, neither name seems intuitively descriptive
>> to me...
> 
> Perhaps.  But asking for output format designed for Porcelain
> implementions to read with --porcelain option has precedence.
> 
>> Why not teach 'git push' to change its output format if it's writing to a pipe?
> 
> That is ugly.  Besides, "writing to a pipe" would not be a right criteria,
> if you want to do
> 
>           git push >log
>           if grep blah log
>           then
>                 do blah thing
>           fi
>           if grep baa log
>           then
>                 do baa thing, too
>           fi
> 
> When you make a program behave differently depending on where your stdout
> goes, typically you see if it is going to the terminal (e.g. isatty(3)),
> but even then you would need an explicit override from the command line
> when stdout is a tty and you do not want "for humans" frills (e.g. color),
> and when stdout is not a tty and you do want such frills.
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23 15:07     ` Marc Branchaud
  2009-06-23 15:38       ` [PATCH] add --plumbing " Larry D'Anna
  2009-06-23 15:50       ` [PATCH] add --porcelain " Junio C Hamano
@ 2009-06-23 18:41       ` Markus Heidelberg
  2 siblings, 0 replies; 13+ messages in thread
From: Markus Heidelberg @ 2009-06-23 18:41 UTC (permalink / raw)
  To: Marc Branchaud; +Cc: Larry D'Anna, git

Marc Branchaud, 23.06.2009:
> Shouldn't this option be named "--plumbing" since it's making 'git
> push' act like plumbing?

git-blame already has --porcelain

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23  1:10   ` [PATCH] add --porcelain option to git-push Larry D'Anna
  2009-06-23 15:07     ` Marc Branchaud
@ 2009-06-23 22:38     ` Constantine Plotnikov
  2009-06-24  0:26       ` Larry D'Anna
  2009-06-25 19:07     ` Junio C Hamano
  2 siblings, 1 reply; 13+ messages in thread
From: Constantine Plotnikov @ 2009-06-23 22:38 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git

On Tue, Jun 23, 2009 at 5:10 AM, Larry D'Anna<larry@elder-gods.org> wrote:
> If --porcelain is used git-push will produce machine-readable output.  The
> output status line for each ref will be tab-separated and sent to stdout instead
> of stderr.  The full symbolic names of the refs will be given.  For example
>
BTW is it possible to have --porcelain + -v together. A machine
readable progress output would come very handy for IDEs and other GUI
tools that use command line tools.

The git tendency to be less verbose when there is no tty is really
annoying from point of view of GUI.

Regards,
Constantine

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23 22:38     ` Constantine Plotnikov
@ 2009-06-24  0:26       ` Larry D'Anna
  0 siblings, 0 replies; 13+ messages in thread
From: Larry D'Anna @ 2009-06-24  0:26 UTC (permalink / raw)
  To: Constantine Plotnikov; +Cc: git

* Constantine Plotnikov (constantine.plotnikov@gmail.com) [090623 18:38]:
> On Tue, Jun 23, 2009 at 5:10 AM, Larry D'Anna<larry@elder-gods.org> wrote:
> > If --porcelain is used git-push will produce machine-readable output.  The
> > output status line for each ref will be tab-separated and sent to stdout instead
> > of stderr.  The full symbolic names of the refs will be given.  For example
> >
> BTW is it possible to have --porcelain + -v together. A machine
> readable progress output would come very handy for IDEs and other GUI
> tools that use command line tools.

My patch makes --porcelain imply some of what -v does, but not all.
Specifically --porcelain will output a status line for each ref that's to be
updated, weather -v is selected or not.  However -v enables some other output
besides that.  There's nothing stopping you from selecting -v and --porcelain.
Basically --porcelain only affects the per-ref status lines.  All other aspects
of git-push are the same.


        --larry

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-23  1:10   ` [PATCH] add --porcelain option to git-push Larry D'Anna
  2009-06-23 15:07     ` Marc Branchaud
  2009-06-23 22:38     ` Constantine Plotnikov
@ 2009-06-25 19:07     ` Junio C Hamano
  2009-06-25 19:30       ` Larry D'Anna
  2009-06-27  0:23       ` [PATCH] add --summary " Larry D'Anna
  2 siblings, 2 replies; 13+ messages in thread
From: Junio C Hamano @ 2009-06-25 19:07 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git

Larry D'Anna <larry@elder-gods.org> writes:

> If --porcelain is used git-push will produce machine-readable output.  The
> output status line for each ref will be tab-separated and sent to stdout instead
> of stderr.  The full symbolic names of the refs will be given.  For example
>
> $ git push --dry-run --porcelain master :foobar 2>/dev/null \
>   | perl -pe 's/\t/ TAB /g'
>
> = TAB refs/heads/master:refs/heads/master TAB [up to date]
> - TAB :refs/heads/foobar TAB [deleted]
> ---

Thanks.  Sign-off?

On a tangent, this reminds me of something that I often find myself
wanting to do.  Currently I do:

	$ git push --dry-run
           A..B master -> master
        $ git log --oneline A..B ;# cut and paste A..B from the output
	$ git push

to achieve what I want; get an overview of what I'd be pushing as the
final sanity check before running the actual push.

I've been wondering if it would be a good idea to teach -v (or some other
option) to do this automatically.  That is,

	$ git push [--dry-run] [--summary[=<n>]]

would give the output from "git log --oneline [-n <n>] A..B".

No, I am not suggesting you to fold such an unrelated feature to your
patch at all.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] add --porcelain option to git-push
  2009-06-25 19:07     ` Junio C Hamano
@ 2009-06-25 19:30       ` Larry D'Anna
  2009-06-27  0:23       ` [PATCH] add --summary " Larry D'Anna
  1 sibling, 0 replies; 13+ messages in thread
From: Larry D'Anna @ 2009-06-25 19:30 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Junio C Hamano wrote:
> Larry D'Anna <larry@elder-gods.org> writes:
>
>   
>> If --porcelain is used git-push will produce machine-readable output.  The
>> output status line for each ref will be tab-separated and sent to stdout instead
>> of stderr.  The full symbolic names of the refs will be given.  For example
>>
>> $ git push --dry-run --porcelain master :foobar 2>/dev/null \
>>   | perl -pe 's/\t/ TAB /g'
>>
>> = TAB refs/heads/master:refs/heads/master TAB [up to date]
>> - TAB :refs/heads/foobar TAB [deleted]
>> ---
>>     
>
> Thanks.  Sign-off?
>
>   
Oops.  Yes, I sign-off on this patch.

    --larry

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] add --summary option to git-push
  2009-06-25 19:07     ` Junio C Hamano
  2009-06-25 19:30       ` Larry D'Anna
@ 2009-06-27  0:23       ` Larry D'Anna
  1 sibling, 0 replies; 13+ messages in thread
From: Larry D'Anna @ 2009-06-27  0:23 UTC (permalink / raw)
  To: git; +Cc: Larry D'Anna

--summary will cause git-push to output a one-line of each commit pushed.
--summary=n will display at most n commits for each ref pushed.

$ git push --dry-run --summary origin :
To /home/larry/gitsandbox/a
   80f0e50..5593a38  master -> master
    5593a38 foo
    81c03f8 bar

Signed-off-by: Larry D'Anna <larry@elder-gods.org>
---
 Documentation/git-push.txt |    6 ++++++
 builtin-push.c             |   12 +++++++++---
 transport.c                |   43 +++++++++++++++++++++++++++++++------------
 transport.h                |    2 +-
 4 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 2653388..803fe36 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -85,6 +85,12 @@ nor in any Push line of the corresponding remotes file---see below).
 --dry-run::
 	Do everything except actually send the updates.
 
+--summary::
+	Print a one-line summary of each commit pushed.
+
+--summary=<n>::
+	Like --summary, but with a limit of <n> commits per ref.
+
 --porcelain::
 	Produce machine-readable output.  The output status line for each ref
 	will be tab-separated and sent to stdout instead of stderr.  The full
diff --git a/builtin-push.c b/builtin-push.c
index 0a0297f..00cf846 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -113,7 +113,7 @@ static void setup_default_push_refspecs(void)
 	}
 }
 
-static int do_push(const char *repo, int flags)
+static int do_push(const char *repo, int flags, int summary)
 {
 	int i, errs;
 	struct remote *remote = remote_get(repo);
@@ -173,7 +173,7 @@ static int do_push(const char *repo, int flags)
 
 		if (flags & TRANSPORT_PUSH_VERBOSE)
 			fprintf(stderr, "Pushing to %s\n", url[i]);
-		err = transport_push(transport, refspec_nr, refspec, flags);
+		err = transport_push(transport, refspec_nr, refspec, flags, summary);
 		err |= transport_disconnect(transport);
 
 		if (!err)
@@ -192,6 +192,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 	int rc;
 	const char *repo = NULL;	/* default repository */
 
+	int summary = 0;
+
 	struct option options[] = {
 		OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
 		OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
@@ -205,6 +207,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
+		{ OPTION_INTEGER, 0, "summary", &summary, "n", "print a summary of [at most n] pushed commits",
+		  PARSE_OPT_OPTARG, NULL, -1
+		},
+
 		OPT_END()
 	};
 
@@ -218,7 +224,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		set_refspecs(argv + 1, argc - 1);
 	}
 
-	rc = do_push(repo, flags);
+	rc = do_push(repo, flags, summary);
 	if (rc == -1)
 		usage_with_options(push_usage, options);
 	else
diff --git a/transport.c b/transport.c
index b074067..562e788 100644
--- a/transport.c
+++ b/transport.c
@@ -750,17 +750,19 @@ static const char *status_abbrev(unsigned char sha1[20])
 	return find_unique_abbrev(sha1, DEFAULT_ABBREV);
 }
 
-static void print_ok_ref_status(struct ref *ref, int porcelain)
+static void print_ok_ref_status(struct ref *ref, int porcelain, int summary)
 {
+	char quickref[84];
+
 	if (ref->deletion)
 		print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
-	else if (is_null_sha1(ref->old_sha1))
+	else if (is_null_sha1(ref->old_sha1)) {
 		print_ref_status('*',
 			(!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
 			"[new branch]"),
 			ref, ref->peer_ref, NULL, porcelain);
-	else {
-		char quickref[84];
+		strcpy (quickref, status_abbrev(ref->new_sha1));
+	} else {
 		char type;
 		const char *msg;
 
@@ -778,9 +780,25 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
 
 		print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
 	}
+
+	if (summary) {
+		FILE *temp = stdout;
+		stdout = stderr;
+		if (summary < 0) {
+			char *argv[] = {"log", "--pretty=format:    %h %s", quickref};
+			cmd_log(3, argv, 0);
+		} else {
+			char dashn[15];
+			sprintf(dashn, "-n%d", summary);
+			char *argv[] = {"log", "--pretty=format:    %h %s", dashn, quickref};
+			cmd_log(4, argv, 0);
+		}
+		fprintf(stderr, "\n");
+		stdout = temp;
+	}
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain, int summary)
 {
 	if (!count)
 		fprintf(stderr, "To %s\n", dest);
@@ -812,7 +830,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 						 "remote failed to report status", porcelain);
 		break;
 	case REF_STATUS_OK:
-		print_ok_ref_status(ref, porcelain);
+		print_ok_ref_status(ref, porcelain, summary);
 		break;
 	}
 
@@ -820,7 +838,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 }
 
 static void print_push_status(const char *dest, struct ref *refs,
-							  int verbose, int porcelain)
+							  int verbose, int porcelain, int summary)
 {
 	struct ref *ref;
 	int n = 0;
@@ -828,18 +846,18 @@ static void print_push_status(const char *dest, struct ref *refs,
 	if (verbose) {
 		for (ref = refs; ref; ref = ref->next)
 			if (ref->status == REF_STATUS_UPTODATE)
-				n += print_one_push_status(ref, dest, n, porcelain);
+				n += print_one_push_status(ref, dest, n, porcelain, summary);
 	}
 
 	for (ref = refs; ref; ref = ref->next)
 		if (ref->status == REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n, porcelain);
+			n += print_one_push_status(ref, dest, n, porcelain, summary);
 
 	for (ref = refs; ref; ref = ref->next) {
 		if (ref->status != REF_STATUS_NONE &&
 		    ref->status != REF_STATUS_UPTODATE &&
 		    ref->status != REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n, porcelain);
+			n += print_one_push_status(ref, dest, n, porcelain, summary);
 	}
 }
 
@@ -997,7 +1015,8 @@ int transport_set_option(struct transport *transport,
 }
 
 int transport_push(struct transport *transport,
-		   int refspec_nr, const char **refspec, int flags)
+				   int refspec_nr, const char **refspec,
+				   int flags, int summary)
 {
 	verify_remote_names(refspec_nr, refspec);
 
@@ -1024,7 +1043,7 @@ int transport_push(struct transport *transport,
 
 		ret = transport->push_refs(transport, remote_refs, flags);
 
-		print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain);
+		print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, summary);
 
 		if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
 			struct ref *ref;
diff --git a/transport.h b/transport.h
index 51b5397..360051e 100644
--- a/transport.h
+++ b/transport.h
@@ -68,7 +68,7 @@ int transport_set_option(struct transport *transport, const char *name,
 			 const char *value);
 
 int transport_push(struct transport *connection,
-		   int refspec_nr, const char **refspec, int flags);
+				   int refspec_nr, const char **refspec, int flags, int summary);
 
 const struct ref *transport_get_remote_refs(struct transport *transport);
 
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2009-06-27  0:23 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-18 21:28 I'd like to be able to know what git-push will do Larry D'Anna
2009-06-22 21:40 ` Jeff King
2009-06-23  1:10   ` [PATCH] add --porcelain option to git-push Larry D'Anna
2009-06-23 15:07     ` Marc Branchaud
2009-06-23 15:38       ` [PATCH] add --plumbing " Larry D'Anna
2009-06-23 15:50       ` [PATCH] add --porcelain " Junio C Hamano
2009-06-23 17:09         ` Marc Branchaud
2009-06-23 18:41       ` Markus Heidelberg
2009-06-23 22:38     ` Constantine Plotnikov
2009-06-24  0:26       ` Larry D'Anna
2009-06-25 19:07     ` Junio C Hamano
2009-06-25 19:30       ` Larry D'Anna
2009-06-27  0:23       ` [PATCH] add --summary " Larry D'Anna

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).