All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiang Xin <worldhello.net@gmail.com>
To: Junio C Hamano <gitster@pobox.com>, Jeff King <peff@peff.net>,
	Git List <git@vger.kernel.org>
Cc: Jiang Xin <zhiyou.jx@alibaba-inc.com>
Subject: [PATCH v14 0/7] New proc-receive hook for centralized workflow
Date: Tue,  5 May 2020 10:41:24 -0400	[thread overview]
Message-ID: <20200505144131.30048-1-worldhello.net@gmail.com> (raw)
In-Reply-To: <CANYiYbFCG1_hdy1kA06wjrvGSQ2=y-hJX3Rsh-rn=X9tcqv1VQ@mail.gmail.com>

From: Jiang Xin <zhiyou.jx@alibaba-inc.com>

This topic introduces a new hook named "proc-receive" for
"receive-pack".  We can use this hook to implement a Gerrit-like
centralized workflow.

## Changes since v13

1. Patch 3/7 introduced a new capability "report-status-v2" for git-push 

   Add new capability "report-status-v2" and new report protocol which is
   not backward compatible for report of git-push.
   
   If a user pushes to a pseudo-reference "refs/for/master/topic", and
   "receive-pack" creates two new references "refs/changes/23/123/1" and
   "refs/changes/24/124/1", for client without the knowledge of
   "report-status-v2", "receive-pack" will only send "ok/ng" directives in
   the report, such as:
   
       ok ref/for/master/topic
   
   But for client which has the knowledge of "report-status-v2",
   "receive-pack" will use "option" directives to report more attributes
   for the reference given by the above "ok/ng" directive.
   
       ok refs/for/master/topic
       option refname refs/changes/23/123/1
       option new-oid <new-oid>
       ok refs/for/master/topic
       option refname refs/changes/24/124/1
       option new-oid <new-oid>
   
   The client will report two new created references to the end user.

2. Patch 2/7: the "proc-receive" reports status using the same way like
   "report-status-v2" to "receive-pack".


## Range-diff v13...v14

1:  dc7f1d044d ! 1:  9a19919552 transport: not report a non-head push as a branch
    @@ t/t5411-proc-receive-hook.sh (new)
     +	git -C upstream.git config http.receivepack true &&
     +	upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
     +	mv upstream.git "$upstream" &&
    ++	set_askpass user@host pass@host &&
     +	git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git
     +'
     +
    @@ t/t5411/test-0000-standard-git-push.sh (new)
     +# Refs of upstream : master(A)  
     +# Refs of workbench: master(A)  tags/v123
     +# git-push         : master(B)             next(A)
    -+test_expect_success "non-force git-push ($PROTOCOL)" '
    ++test_expect_success "git-push ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		$B:refs/heads/master \
     +		HEAD:refs/heads/next \
    @@ t/t5411/test-0000-standard-git-push.sh (new)
     +# Refs of upstream : master(B)  next(A)
     +# Refs of workbench: master(A)           tags/v123
     +# git-push -f      : master(A)  NULL     tags/v123  refs/review/master/topic(A)  a/b/c(A)
    -+test_expect_success "force git-push ($PROTOCOL)" '
    ++test_expect_success "git-push -f ($PROTOCOL)" '
     +	git -C workbench push -f origin \
     +		refs/tags/v123 \
     +		:refs/heads/next \
    @@ t/t5411/test-0001-standard-git-push--porcelain.sh (new)
     +# Refs of upstream : master(A)  
     +# Refs of workbench: master(A)  tags/v123
     +# git-push         : master(B)             next(A)
    -+test_expect_success "non-force git-push (--porcelain, $PROTOCOL)" '
    ++test_expect_success "git-push ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		$B:refs/heads/master \
     +		HEAD:refs/heads/next \
    @@ t/t5411/test-0001-standard-git-push--porcelain.sh (new)
     +# Refs of upstream : master(B)  next(A)
     +# Refs of workbench: master(A)           tags/v123
     +# git-push -f      : master(A)  NULL     tags/v123  refs/review/master/topic(A)  a/b/c(A)
    -+test_expect_success "force git-push (--porcelain, $PROTOCOL)" '
    ++test_expect_success "git-push -f ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain -f origin \
     +		refs/tags/v123 \
     +		:refs/heads/next \
    @@ t/t5411/test-0001-standard-git-push--porcelain.sh (new)
     +		git update-ref -d refs/heads/a/b/c
     +	)
     +'
    -+
     
      ## t/t5411/test-0002-pre-receive-declined.sh (new) ##
     @@
    -+test_expect_success "setup pre-receive hook (declined, $PROTOCOL)" '
    ++test_expect_success "setup pre-receive hook ($PROTOCOL)" '
     +	mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" &&
     +	write_script "$upstream/hooks/pre-receive" <<-EOF
     +	exit 1
    @@ t/t5411/test-0002-pre-receive-declined.sh (new)
     
      ## t/t5411/test-0003-pre-receive-declined--porcelain.sh (new) ##
     @@
    -+test_expect_success "setup pre-receive hook (declined, $PROTOCOL)" '
    ++test_expect_success "setup pre-receive hook ($PROTOCOL)" '
     +	mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" &&
     +	write_script "$upstream/hooks/pre-receive" <<-EOF
     +	exit 1
    @@ t/t5411/test-0003-pre-receive-declined--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git-push         : master(B)             next(A)
    -+test_expect_success "git-push is declined (--porcelain, $PROTOCOL)" '
    ++test_expect_success "git-push is declined ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		$B:refs/heads/master \
     +		HEAD:refs/heads/next \
2:  673f44599f < -:  ---------- connect: export parse_feature_value()
3:  43647b379a ! 2:  f1a3ca9cda receive-pack: add new proc-receive hook
    @@ Commit message
             # NO, I reject it.
             H: PKT-LINE(ng <ref> <reason>)
             # Fall through, let 'receive-pack' to execute it.
    -        H: PKT-LINE(ft <ref>)
    +        H: PKT-LINE(ok <ref>)
    +        H: PKT-LINE(option fall-through)
             # OK, but has an alternate reference.  The alternate reference name
    -        # is given in the third parameter, and other status can be given in
    -        # key-value pairs.
    -        H: PKT-LINE(alt <ref> <alt-ref> old-oid=<old-oid> new-oid=<new-oid>
    -                    forced-update)
    +        # and other status can be given in options
    +        H: PKT-LINE(ok <ref>)
    +        H: PKT-LINE(option refname <refname>)
    +        H: PKT-LINE(option old-oid <old-oid>)
    +        H: PKT-LINE(option new-oid <new-oid>)
    +        H: PKT-LINE(option forced-update)
             H: ... ...
             H: flush-pkt
     
    @@ Commit message
         create/update different reference.  For example, a command for a pseudo
         reference "refs/for/master/topic" may create/update different reference
         such as "refs/pull/123/head".  The alternate reference name and other
    -    status are given in key-value pairs as extended status of the report
    -    line.
    +    status are given in option lines.
     
         The list of commands returned from "proc-receive" will replace the
         relevant commands that are sent from user to "receive-pack", and
    @@ Commit message
         other routines.  Finally, the result of the execution of these commands
         will be reported to end user.
     
    -    The reporting function from "receive-pack" to "send-pack" is extended
    -    using a backward compatible way by adding key-value pairs after an null
    -    character, like:
    -
    -        # OK, run this command successfully with optional extended-status.
    -        ok <reference>\0ref=refs/pull/123/head old-oid=...
    -
    -        # NO, I reject it.
    -        ng <reference> <error message>
    -
    -    Parsing the extended status of the report lines for "send-pack" is not
    -    implemented in this commit, so we can make a compatible test on old
    -    version of a Git client.
    +    The reporting function from "receive-pack" to "send-pack" will be
    +    extended in latter commit just like what the "proc-receive" hook reports
    +    to "receive-pack".
     
         Suggested-by: Junio C Hamano <gitster@pobox.com>
         Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>
    @@ builtin/receive-pack.c: static void write_head_info(void)
     +#define RUN_PROC_RECEIVE_RETURNED	2
      struct command {
      	struct command *next;
    - 	const char *error_string;
    -+	const char *extended_status;
    +-	const char *error_string;
    ++	struct ref_push_report report;
      	unsigned int skip_update:1,
     -		     did_not_exist:1;
     +		     did_not_exist:1,
    @@ builtin/receive-pack.c: static void write_head_info(void)
      	int index;
      	struct object_id old_oid;
      	struct object_id new_oid;
    +@@ builtin/receive-pack.c: static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
    + 	struct command *cmd = state->cmd;
    + 
    + 	while (cmd &&
    +-	       state->skip_broken && (cmd->error_string || cmd->did_not_exist))
    ++	       state->skip_broken && (cmd->report.error_message || cmd->did_not_exist))
    + 		cmd = cmd->next;
    + 	if (!cmd)
    + 		return -1; /* EOF */
     @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
      	return finish_command(&proc);
      }
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
     +{
     +	struct command *cmd;
     +	struct command *hint = NULL;
    -+	struct strbuf extended_status = STRBUF_INIT;
     +	int code = 0;
    ++	int new_options = 1;
     +
     +	for (;;) {
     +		struct object_id old_oid, new_oid;
    -+		const char *status;
    -+		char *refname;
    -+		char *remains = NULL;
    ++		const char *head;
    ++		const char *refname;
    ++		char *p;
     +
     +		if (packet_reader_read(reader) != PACKET_READ_NORMAL)
     +			break;
    -+		status = reader->line;
    -+		refname = strchr(status, ' ');
    -+		if (refname) {
    -+			*refname++ = '\0';
    -+			remains = strchr(refname, ' ');
    -+			if (remains)
    -+				*remains++ = '\0';
    ++
    ++		head = reader->line;
    ++		p = strchr(head, ' ');
    ++		if (!p) {
    ++			strbuf_addf(errmsg, "proc-receive reported incomplete status line: '%s'\n", head);
    ++			code = -1;
    ++			continue;
     +		}
    -+		if (!refname || strlen(refname) == 0) {
    -+			strbuf_addf(errmsg, "proc-receive expected '<status> <ref> ...', got '%s'\n",
    -+				    reader->line);
    ++		*p++ = '\0';
    ++		if (!strcmp(head, "option")) {
    ++			struct ref_push_report_options *options;
    ++			const char *key, *val;
    ++
    ++			if (!hint) {
    ++			       if (new_options) {
    ++					strbuf_addstr(errmsg, "proc-receive reported 'option' without a matching 'ok/ng' directive\n");
    ++					new_options = 0;
    ++				}
    ++				code = -1;
    ++				continue;
    ++			}
    ++			options = hint->report.options;
    ++			while (options && options->next)
    ++				options = options->next;
    ++			if (new_options) {
    ++				if (!options) {
    ++					hint->report.options = xcalloc(1, sizeof(struct ref_push_report_options));
    ++					options = hint->report.options;
    ++				} else {
    ++					options->next = xcalloc(1, sizeof(struct ref_push_report_options));
    ++					options = options->next;
    ++				}
    ++				new_options = 0;
    ++			}
    ++			assert(options);
    ++			key = p;
    ++			p = strchr(key, ' ');
    ++			if (p)
    ++				*p++ = '\0';
    ++			val = p;
    ++			if (!strcmp(key, "refname"))
    ++				options->ref_name = xstrdup_or_null(val);
    ++			else if (!strcmp(key, "old-oid") && val &&
    ++				 !parse_oid_hex(val, &old_oid, &val))
    ++				options->old_oid = oiddup(&old_oid);
    ++			else if (!strcmp(key, "new-oid") && val &&
    ++				 !parse_oid_hex(val, &new_oid, &val))
    ++				options->new_oid = oiddup(&new_oid);
    ++			else if (!strcmp(key, "forced-update"))
    ++				options->forced_update = 1;
    ++			else if (!strcmp(key, "fall-through"))
    ++				/* Fall through, let 'receive-pack' to execute it. */
    ++				hint->run_proc_receive = 0;
    ++			continue;
    ++		}
    ++
    ++		refname = p;
    ++		p = strchr(refname, ' ');
    ++		if (p)
    ++			*p++ = '\0';
    ++		if (strcmp(head, "ok") && strcmp(head, "ng")) {
    ++			strbuf_addf(errmsg, "proc-receive reported bad status '%s' on ref '%s'\n",
    ++				    head, refname);
     +			code = -1;
     +			continue;
     +		}
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
     +		if (!hint) {
     +			strbuf_addf(errmsg, "proc-receive reported status on unknown ref: %s\n",
     +				    refname);
    ++			code = -1;
     +			continue;
     +		}
     +		if (!hint->run_proc_receive) {
     +			strbuf_addf(errmsg, "proc-receive reported status on unexpected ref: %s\n",
     +				    refname);
    ++			code = -1;
     +			continue;
     +		}
    -+		if (!strcmp(status, "ng")) {
    -+			if (remains)
    -+				hint->error_string = xstrdup(remains);
    ++		if (!strcmp(head, "ng")) {
    ++			if (p)
    ++				hint->report.error_message = xstrdup(p);
     +			else
    -+				hint->error_string = "failed";
    ++				hint->report.error_message = "failed";
     +			code = -1;
    -+		} else if (!strcmp("ft", status)) {
    -+			/* Reset "run_proc_receive" field, and continue to run in "receive-pack" */
    -+			hint->run_proc_receive = 0;
    -+		} else if (!strcmp("alt", status)) {
    -+			char *alt_ref = NULL;
    -+			char *p1, *p2;
    -+
    -+			if (!remains) {
    -+				strbuf_addf(errmsg, "proc-receive expected 'alt <ref> <alt-ref> ...', got 'alt %s'\n",
    -+					    refname);
    -+				continue;
    -+			}
    -+			p1 = strchr(remains, '=');
    -+			p2 = strchr(remains, ' ');
    -+			if (!p1) {
    -+				/*
    -+				 * "alt <ref> <alt-ref>", or
    -+				 * "alt <ref> <alt-ref> forced-update"
    -+				 */
    -+				alt_ref = remains;
    -+				remains = p2;
    -+				if (remains)
    -+					*remains++ = '\0';
    -+			} else if (!p2) {
    -+				/* "alt <ref> old-oid=<oid>" */
    -+				alt_ref = NULL;
    -+			} else if (p1 > p2) {
    -+				/* "alt <ref> <alt-ref> old-oid=<oid>" */
    -+				alt_ref = remains;
    -+				remains = p2;
    -+				if (remains)
    -+					*remains++ = '\0';
    -+			} else {
    -+				/* "alt <ref> old-oid=<oid1> new-oid=<oid2>" */
    -+				alt_ref = NULL;
    -+			}
    -+
    -+			if (hint->extended_status)
    -+				strbuf_addstr(&extended_status, hint->extended_status);
    -+
    -+			/*
    -+			 * Already received an "ok <ref>" response, add an
    -+			 * additional "ref=<ref>" field.
    -+			 */
    -+			if (extended_status.len == 0 &&
    -+			    hint->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)
    -+				strbuf_addf(&extended_status, "ref=%s", refname);
    -+
    -+			if (alt_ref)
    -+				strbuf_addf(&extended_status, "%sref=%s",
    -+					    extended_status.len > 0 ? " ": "",
    -+					    alt_ref);
    -+			else if (extended_status.len > 0)
    -+				/*
    -+				 * Start new extended status for refname, if it
    -+				 * is not the first report for this reference.
    -+				 */
    -+				strbuf_addf(&extended_status, " ref=%s", refname);
    -+
    -+			if (remains) {
    -+				const char *val;
    -+				int len;
    -+
    -+				val = parse_feature_value(remains, "old-oid", &len);
    -+				if (val && len > 0)
    -+					if (!parse_oid_hex(val, &old_oid, &val))
    -+						strbuf_addf(&extended_status, "%sold-oid=%s",
    -+							   extended_status.len > 0 ? " ": "",
    -+							   oid_to_hex(&old_oid));
    -+
    -+				val = parse_feature_value(remains, "new-oid", &len);
    -+				if (val && len > 0)
    -+					if (!parse_oid_hex(val, &new_oid, &val))
    -+						strbuf_addf(&extended_status, "%snew-oid=%s",
    -+							   extended_status.len > 0 ? " ": "",
    -+							   oid_to_hex(&new_oid));
    -+
    -+				if (parse_feature_request(remains, "forced-update"))
    -+					strbuf_addf(&extended_status, "%sforced-update",
    -+						    extended_status.len > 0 ? " ": "");
    -+			}
    -+
    -+			if (extended_status.len > 0) {
    -+				free((void *)hint->extended_status);
    -+				hint->extended_status = strbuf_detach(&extended_status, NULL);
    -+			}
    -+		} else if (strcmp("ok", status)) {
    -+			strbuf_addf(errmsg, "proc-receive reported bad status '%s' on ref '%s'\n",
    -+				    status, refname);
    -+			code = -1;
    -+			/* Skip marking it as RUN_PROC_RECEIVE_RETURNED */
    -+			continue;
     +		}
    -+
     +		if (hint->run_proc_receive)
     +			hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
    ++		new_options = 1;
     +	}
     +
     +	for (cmd = commands; cmd; cmd = cmd->next)
    -+		if (cmd->run_proc_receive && !cmd->error_string &&
    ++		if (cmd->run_proc_receive && !cmd->report.error_message &&
     +		    !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) {
    -+		    cmd->error_string = "proc-receive failed to report status";
    ++		    cmd->report.error_message = "proc-receive failed to report status";
     +		    code = -1;
     +		}
    -+
     +	return code;
     +}
     +
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
     +	struct packet_reader reader;
     +	struct strbuf cap = STRBUF_INIT;
     +	struct strbuf errmsg = STRBUF_INIT;
    -+	int pr_use_push_options = 0;
    ++	int hook_use_push_options = 0;
     +	int version = 0;
     +	int code;
     +
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
     +			if (linelen < reader.pktlen) {
     +				const char *feature_list = reader.line + linelen + 1;
     +				if (parse_feature_request(feature_list, "push-options"))
    -+					pr_use_push_options = 1;
    ++					hook_use_push_options = 1;
     +			}
     +		}
     +	}
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
     +
     +	/* Send commands */
     +	for (cmd = commands; cmd; cmd = cmd->next) {
    -+		if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string)
    ++		if (!cmd->run_proc_receive || cmd->skip_update || cmd->report.error_message)
     +			continue;
     +		packet_write_fmt(proc.in, "%s %s %s",
     +				 oid_to_hex(&cmd->old_oid),
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
     +	packet_flush(proc.in);
     +
     +	/* Send push options */
    -+	if (pr_use_push_options) {
    ++	if (hook_use_push_options) {
     +		struct string_list_item *item;
     +
     +		for_each_string_list_item(item, push_options)
    @@ builtin/receive-pack.c: static int run_update_hook(struct command *cmd)
      static char *refuse_unconfigured_deny_msg =
      	N_("By default, updating the current branch in a non-bare repository\n"
      	   "is denied, because it will make the index and work tree inconsistent\n"
    +@@ builtin/receive-pack.c: static void run_update_post_hook(struct command *commands)
    + 		return;
    + 
    + 	for (cmd = commands; cmd; cmd = cmd->next) {
    +-		if (cmd->error_string || cmd->did_not_exist)
    ++		if (cmd->report.error_message || cmd->did_not_exist)
    + 			continue;
    + 		if (!proc.args.argc)
    + 			argv_array_push(&proc.args, hook);
    +@@ builtin/receive-pack.c: static void check_aliased_update_internal(struct command *cmd,
    + 	if (!dst_name) {
    + 		rp_error("refusing update to broken symref '%s'", cmd->ref_name);
    + 		cmd->skip_update = 1;
    +-		cmd->error_string = "broken symref";
    ++		cmd->report.error_message = "broken symref";
    + 		return;
    + 	}
    + 	dst_name = strip_namespace(dst_name);
    +@@ builtin/receive-pack.c: static void check_aliased_update_internal(struct command *cmd,
    + 		 find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV),
    + 		 find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV));
    + 
    +-	cmd->error_string = dst_cmd->error_string =
    ++	cmd->report.error_message = dst_cmd->report.error_message =
    + 		"inconsistent aliased update";
    + }
    + 
    +@@ builtin/receive-pack.c: static void check_aliased_updates(struct command *commands)
    + 	string_list_sort(&ref_list);
    + 
    + 	for (cmd = commands; cmd; cmd = cmd->next) {
    +-		if (!cmd->error_string)
    ++		if (!cmd->report.error_message)
    + 			check_aliased_update(cmd, &ref_list);
    + 	}
    + 
    +@@ builtin/receive-pack.c: static void set_connectivity_errors(struct command *commands,
    + 				     &opt))
    + 			continue;
    + 
    +-		cmd->error_string = "missing necessary objects";
    ++		cmd->report.error_message = "missing necessary objects";
    + 	}
    + }
    + 
    +@@ builtin/receive-pack.c: static void reject_updates_to_hidden(struct command *commands)
    + 	prefix_len = refname_full.len;
    + 
    + 	for (cmd = commands; cmd; cmd = cmd->next) {
    +-		if (cmd->error_string)
    ++		if (cmd->report.error_message)
    + 			continue;
    + 
    + 		strbuf_setlen(&refname_full, prefix_len);
    +@@ builtin/receive-pack.c: static void reject_updates_to_hidden(struct command *commands)
    + 		if (!ref_is_hidden(cmd->ref_name, refname_full.buf))
    + 			continue;
    + 		if (is_null_oid(&cmd->new_oid))
    +-			cmd->error_string = "deny deleting a hidden ref";
    ++			cmd->report.error_message = "deny deleting a hidden ref";
    + 		else
    +-			cmd->error_string = "deny updating a hidden ref";
    ++			cmd->report.error_message = "deny updating a hidden ref";
    + 	}
    + 
    + 	strbuf_release(&refname_full);
    +@@ builtin/receive-pack.c: static void reject_updates_to_hidden(struct command *commands)
    + 
    + static int should_process_cmd(struct command *cmd)
    + {
    +-	return !cmd->error_string && !cmd->skip_update;
    ++	return !cmd->report.error_message && !cmd->skip_update;
    + }
    + 
    + static void warn_if_skipped_connectivity_check(struct command *commands,
     @@ builtin/receive-pack.c: static void execute_commands_non_atomic(struct command *commands,
      	struct strbuf err = STRBUF_INIT;
      
    @@ builtin/receive-pack.c: static void execute_commands_non_atomic(struct command *
      			continue;
      
      		transaction = ref_transaction_begin(&err);
    + 		if (!transaction) {
    + 			rp_error("%s", err.buf);
    + 			strbuf_reset(&err);
    +-			cmd->error_string = "transaction failed to start";
    ++			cmd->report.error_message = "transaction failed to start";
    + 			continue;
    + 		}
    + 
    +-		cmd->error_string = update(cmd, si);
    ++		cmd->report.error_message = update(cmd, si);
    + 
    +-		if (!cmd->error_string
    ++		if (!cmd->report.error_message
    + 		    && ref_transaction_commit(transaction, &err)) {
    + 			rp_error("%s", err.buf);
    + 			strbuf_reset(&err);
    +-			cmd->error_string = "failed to update ref";
    ++			cmd->report.error_message = "failed to update ref";
    + 		}
    + 		ref_transaction_free(transaction);
    + 	}
     @@ builtin/receive-pack.c: static void execute_commands_atomic(struct command *commands,
      	}
      
    @@ builtin/receive-pack.c: static void execute_commands_atomic(struct command *comm
     +		if (!should_process_cmd(cmd) || cmd->run_proc_receive)
      			continue;
      
    - 		cmd->error_string = update(cmd, si);
    +-		cmd->error_string = update(cmd, si);
    ++		cmd->report.error_message = update(cmd, si);
    + 
    +-		if (cmd->error_string)
    ++		if (cmd->report.error_message)
    + 			goto failure;
    + 	}
    + 
    +@@ builtin/receive-pack.c: static void execute_commands_atomic(struct command *commands,
    + 
    + failure:
    + 	for (cmd = commands; cmd; cmd = cmd->next)
    +-		if (!cmd->error_string)
    +-			cmd->error_string = reported_error;
    ++		if (!cmd->report.error_message)
    ++			cmd->report.error_message = reported_error;
    + 
    + cleanup:
    + 	ref_transaction_free(transaction);
     @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
      	struct iterate_data data;
      	struct async muxer;
    @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
      
      	if (unpacker_error) {
      		for (cmd = commands; cmd; cmd = cmd->next)
    +-			cmd->error_string = "unpacker error";
    ++			cmd->report.error_message = "unpacker error";
    + 		return;
    + 	}
    + 
     @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
      
      	reject_updates_to_hidden(commands);
    @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
     +
      	if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
      		for (cmd = commands; cmd; cmd = cmd->next) {
    - 			if (!cmd->error_string)
    +-			if (!cmd->error_string)
    +-				cmd->error_string = "pre-receive hook declined";
    ++			if (!cmd->report.error_message)
    ++				cmd->report.error_message = "pre-receive hook declined";
    + 		}
    + 		return;
    + 	}
    +@@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
    + 	 */
    + 	if (tmp_objdir_migrate(tmp_objdir) < 0) {
    + 		for (cmd = commands; cmd; cmd = cmd->next) {
    +-			if (!cmd->error_string)
    +-				cmd->error_string = "unable to migrate objects to permanent storage";
    ++			if (!cmd->report.error_message)
    ++				cmd->report.error_message = "unable to migrate objects to permanent storage";
    + 		}
    + 		return;
    + 	}
     @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
      	free(head_name_to_free);
      	head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
    @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
     +	if (run_proc_receive &&
     +	    run_proc_receive_hook(commands, push_options))
     +		for (cmd = commands; cmd; cmd = cmd->next)
    -+			if (!cmd->error_string  && (cmd->run_proc_receive || use_atomic))
    -+				cmd->error_string = "fail to run proc-receive hook";
    ++			if (!cmd->report.error_message  && (cmd->run_proc_receive || use_atomic))
    ++				cmd->report.error_message = "fail to run proc-receive hook";
     +
      	if (use_atomic)
      		execute_commands_atomic(commands, si);
      	else
    +@@ builtin/receive-pack.c: static void update_shallow_info(struct command *commands,
    + 		if (is_null_oid(&cmd->new_oid))
    + 			continue;
    + 		if (ref_status[cmd->index]) {
    +-			cmd->error_string = "shallow update not allowed";
    ++			cmd->report.error_message = "shallow update not allowed";
    + 			cmd->skip_update = 1;
    + 		}
    + 	}
     @@ builtin/receive-pack.c: static void report(struct command *commands, const char *unpack_status)
      	packet_buf_write(&buf, "unpack %s\n",
      			 unpack_status ? unpack_status : "ok");
      	for (cmd = commands; cmd; cmd = cmd->next) {
     -		if (!cmd->error_string)
    --			packet_buf_write(&buf, "ok %s\n",
    ++		if (!cmd->report.error_message)
    + 			packet_buf_write(&buf, "ok %s\n",
     -					 cmd->ref_name);
    --		else
    --			packet_buf_write(&buf, "ng %s %s\n",
    --					 cmd->ref_name, cmd->error_string);
    -+		if (!cmd->error_string) {
    -+			if (cmd->extended_status)
    -+				packet_buf_write(&buf, "ok %s%c%s\n",
    -+						 cmd->ref_name, '\0',
    -+						 cmd->extended_status);
    -+			else
    -+				packet_buf_write(&buf, "ok %s\n",
     +						 cmd->ref_name);
    -+		} else {
    -+			if (cmd->extended_status)
    -+				packet_buf_write(&buf, "ng %s %s%c%s\n",
    -+						 cmd->ref_name, cmd->error_string,
    -+						 '\0', cmd->extended_status);
    -+			else
    -+				packet_buf_write(&buf, "ng %s %s\n",
    -+						 cmd->ref_name, cmd->error_string);
    -+		}
    + 		else
    + 			packet_buf_write(&buf, "ng %s %s\n",
    +-					 cmd->ref_name, cmd->error_string);
    ++					 cmd->ref_name, cmd->report.error_message);
      	}
      	packet_buf_flush(&buf);
      
    +@@ builtin/receive-pack.c: int cmd_receive_pack(int argc, const char **argv, const char *prefix)
    + 		if (!check_cert_push_options(&push_options)) {
    + 			struct command *cmd;
    + 			for (cmd = commands; cmd; cmd = cmd->next)
    +-				cmd->error_string = "inconsistent push options";
    ++				cmd->report.error_message = "inconsistent push options";
    + 		}
    + 
    + 		prepare_shallow_info(&si, &shallow);
    +
    + ## remote.h ##
    +@@ remote.h: int for_each_remote(each_remote_fn fn, void *priv);
    + 
    + int remote_has_url(struct remote *remote, const char *url);
    + 
    ++struct ref_push_report_options {
    ++	char *ref_name;
    ++	struct object_id *old_oid;
    ++	struct object_id *new_oid;
    ++	unsigned int forced_update:1;
    ++	struct ref_push_report_options *next;
    ++};
    ++
    ++struct ref_push_report {
    ++	const char *message;
    ++	const char *error_message;
    ++	struct ref_push_report_options *options;
    ++};
    ++
    + struct ref {
    + 	struct ref *next;
    + 	struct object_id old_oid;
     
      ## t/helper/test-proc-receive.c (new) ##
     @@
    @@ t/t5411/test-0012-no-hook-error--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       next(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: no hook, fail to push special ref (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: no hook, fail to push special ref ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:next \
     +		HEAD:refs/for/master/topic \
    @@ t/t5411/test-0012-no-hook-error--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push --atomic: (B)                   next(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: no hook, all failed for atomic push (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: no hook, all failed for atomic push ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain --atomic origin \
     +		$B:master \
     +		HEAD:next \
    @@ t/t5411/test-0013-bad-protocol.sh (new)
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok
    -+	remote: error: proc-receive expected "<status> <ref> ...", got "ok"
    ++	remote: error: proc-receive reported incomplete status line: "ok"
     +	To <URL/of/upstream.git>
     +	 ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
     +	EOF
    @@ t/t5411/test-0014-bad-protocol--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: bad protocol (unknown version, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0014-bad-protocol--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       next(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: bad protocol (no report, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/heads/next \
     +		HEAD:refs/for/master/topic >out 2>&1 &&
    @@ t/t5411/test-0014-bad-protocol--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic
    -+test_expect_success "proc-receive: bad protocol (no ref, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic\
     +		>out 2>&1 &&
    @@ t/t5411/test-0014-bad-protocol--porcelain.sh (new)
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok
    -+	remote: error: proc-receive expected "<status> <ref> ...", got "ok"
    ++	remote: error: proc-receive reported incomplete status line: "ok"
     +	To <URL/of/upstream.git>
     +	!    HEAD:refs/for/master/topic    [remote rejected] (proc-receive failed to report status)
     +	Done
    @@ t/t5411/test-0014-bad-protocol--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic
    -+test_expect_success "proc-receive: bad protocol (unknown status, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +			HEAD:refs/for/master/topic \
     +			>out 2>&1 &&
    @@ t/t5411/test-0021-report-ng--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic
    -+test_expect_success "proc-receive: fail to update (ng, no message, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0021-report-ng--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic
    -+test_expect_success "proc-receive: fail to update (ng, with message, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: fail to update (ng, with message, $PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0023-report-unexpect-ref--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         : (B)                   refs/for/master/topic
    -+test_expect_success "proc-receive: report unexpected ref (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report unexpected ref ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		$B:refs/heads/master \
     +		HEAD:refs/for/master/topic \
    @@ t/t5411/test-0025-report-unknown-ref--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/a/b/c/my/topic
    -+test_expect_success "proc-receive: report unknown reference (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report unknown reference ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/for/a/b/c/my/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0027-push-options--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push -o ...  :                       refs/for/master/topic
    -+test_expect_success "proc-receive: not support push options (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: not support push options ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push \
     +		--porcelain \
     +		-o issue=123 \
    @@ t/t5411/test-0027-push-options--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push -o ...  :                       next(A)  refs/for/master/topic
    -+test_expect_success "proc-receive: push with options (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: push with options ($PROTOCOL/porcelain)" '
     +	git -C workbench push \
     +		--porcelain \
     +		--atomic \
    @@ t/t5411/test-0031-report-ok--porcelain.sh (new)
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic
    -+test_expect_success "proc-receive: ok (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: ok ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0031-report-ok--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     
    - ## t/t5411/test-0032-report-alt.sh (new) ##
    + ## t/t5411/test-0032-report-with-options.sh (new) ##
     @@
    -+test_expect_success "setup proc-receive hook (alt <ref>, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic"
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option old-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref>, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option without matching ok ($PROTOCOL)" '
     +	test_must_fail git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic
    -+	remote: error: proc-receive expected "alt <ref> <alt-ref> ...", got "alt refs/for/master/topic"
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: error: proc-receive reported "option" without a matching "ok/ng" directive
     +	To <URL/of/upstream.git>
     +	 ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
     +	EOF
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> <alt-ref>, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option refname, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/pull/123/head"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> <alt-ref>, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option refname ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> <alt-ref> forced-update, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/pull/123/head forced-update"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option forced-update"
     +	EOF
     +'
    -+
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> <alt-ref> forced-update, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head forced-update
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option forced-update
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> <alt-ref> old-oid=X, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/pull/123/head old-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option old-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> <alt-ref> old-oid=X, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head old-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> old-oid=X, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic old-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> old-oid=X, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> old-oid=X new-oid=Y, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic old-oid=$A new-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> old-oid=X new-oid=Y, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (with multiple alt reports, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
     +		-r "ok refs/for/a/b/c/topic" \
    -+		-r "alt refs/for/next/topic refs/pull/123/head" \
    -+		-r "alt refs/for/master/topic refs/pull/124/head old-oid=$B forced-update new-oid=$A"
    ++		-r "ok refs/for/next/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/124/head" \
    ++		-r "option old-oid $B" \
    ++		-r "option forced-update" \
    ++		-r "option new-oid $A"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: with multiple alt reports ($PROTOCOL)" '
    ++test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/next/topic \
     +		HEAD:refs/for/a/b/c/topic \
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok refs/for/a/b/c/topic
    -+	remote: proc-receive> alt refs/for/next/topic refs/pull/123/head
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/124/head old-oid=<COMMIT-B> forced-update new-oid=<COMMIT-A>
    ++	remote: proc-receive> ok refs/for/next/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/124/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: proc-receive> option forced-update
    ++	remote: proc-receive> option new-oid <COMMIT-A>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
    @@ t/t5411/test-0032-report-alt.sh (new)
     +	test_cmp expect actual
     +'
     
    - ## t/t5411/test-0033-report-alt--porcelain.sh (new) ##
    + ## t/t5411/test-0033-report-with-options--porcelain.sh (new) ##
     @@
    -+test_expect_success "setup proc-receive hook (alt <ref>, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic"
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option old-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref>, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option without matching ok ($PROTOCOL/porcelain)" '
     +	test_must_fail git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic
    -+	remote: error: proc-receive expected "alt <ref> <alt-ref> ...", got "alt refs/for/master/topic"
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: error: proc-receive reported "option" without a matching "ok/ng" directive
     +	To <URL/of/upstream.git>
     +	!    HEAD:refs/for/master/topic    [remote rejected] (proc-receive failed to report status)
     +	Done
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> <alt-ref>, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option refname, $PROTOCOL/porcelain)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/pull/123/head"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> <alt-ref>, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> <alt-ref> forced-update, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/pull/123/head forced-update"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option forced-update"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> <alt-ref> forced-update, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head forced-update
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option forced-update
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> <alt-ref> old-oid=X, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/pull/123/head old-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option old-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> <alt-ref> old-oid=X, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head old-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> old-oid=X, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic old-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> old-oid=X, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (alt <ref> old-oid=X new-oid=Y, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL/porcelain)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic old-oid=$A new-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report alt (alt <ref> old-oid=X new-oid=Y, --porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (with multiple alt reports, --porcelain, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL/porcelain)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
     +		-r "ok refs/for/a/b/c/topic" \
    -+		-r "alt refs/for/next/topic refs/pull/123/head" \
    -+		-r "alt refs/for/master/topic refs/pull/124/head old-oid=$B forced-update new-oid=$A"
    ++		-r "ok refs/for/next/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/124/head" \
    ++		-r "option old-oid $B" \
    ++		-r "option forced-update" \
    ++		-r "option new-oid $A"
    ++
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/next/topic(A)  refs/for/a/b/c/topic(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: with multiple alt reports (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/next/topic \
     +		HEAD:refs/for/a/b/c/topic \
    @@ t/t5411/test-0033-report-alt--porcelain.sh (new)
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok refs/for/a/b/c/topic
    -+	remote: proc-receive> alt refs/for/next/topic refs/pull/123/head
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/124/head old-oid=<COMMIT-B> forced-update new-oid=<COMMIT-A>
    ++	remote: proc-receive> ok refs/for/next/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/124/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: proc-receive> option forced-update
    ++	remote: proc-receive> option new-oid <COMMIT-A>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
    @@ t/t5411/test-0034-report-ft.sh (new)
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "ft refs/for/master/topic"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option fall-through"
     +	EOF
     +'
     +
    @@ t/t5411/test-0034-report-ft.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
    -+	remote: proc-receive> ft refs/for/master/topic
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option fall-through
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0034-report-ft.sh (new)
     
      ## t/t5411/test-0035-report-ft--porcelain.sh (new) ##
     @@
    -+test_expect_success "setup proc-receive hook (ft, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (fall-through, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "ft refs/for/master/topic"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option fall-through"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(B)
    -+test_expect_success "proc-receive: fall throught, let receive-pack to execute (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		$B:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0035-report-ft--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
    -+	remote: proc-receive> ft refs/for/master/topic
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option fall-through
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0035-report-ft--porcelain.sh (new)
     +	git -C "$upstream" update-ref -d refs/for/master/topic
     +'
     
    - ## t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new) ##
    + ## t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh (new) ##
     @@
    -+test_expect_success "setup proc-receive hook (multiple alt, no alt-ref for the 1st resp, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic old-oid=$A new-oid=$B" \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/1 old-oid=$ZERO_OID new-oid=$A" \
    -+		-r "alt refs/for/master/topic refs/changes/25/125/1 old-oid=$A new-oid=$B"
    -+	EOF
    -+'
    -+
    -+# Refs of upstream : master(A)
    -+# Refs of workbench: master(A)  tags/v123
    -+# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report multiple alt, no alt-ref for the 1st resp ($PROTOCOL)" '
    -+	git -C workbench push origin \
    -+		HEAD:refs/for/master/topic \
    -+		>out 2>&1 &&
    -+	make_user_friendly_and_stable_output <out >actual &&
    -+	cat >expect <<-EOF &&
    -+	remote: # pre-receive hook
    -+	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: # proc-receive hook
    -+	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/1 old-oid=<ZERO-OID> new-oid=<COMMIT-A>
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/25/125/1 old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: # post-receive hook
    -+	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	To <URL/of/upstream.git>
    -+	 * [new reference] HEAD -> refs/for/master/topic
    -+	EOF
    -+	test_cmp expect actual &&
    -+	git -C "$upstream" show-ref >out &&
    -+	make_user_friendly_and_stable_output <out >actual &&
    -+	cat >expect <<-EOF &&
    -+	<COMMIT-A> refs/heads/master
    -+	EOF
    -+	test_cmp expect actual
    -+'
    -+
    -+test_expect_success "setup proc-receive hook (multiple alt, no alt-ref for the 2nd resp, $PROTOCOL)" '
    -+	write_script "$upstream/hooks/proc-receive" <<-EOF
    -+	printf >&2 "# proc-receive hook\n"
    -+	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/1 old-oid=$ZERO_OID new-oid=$A" \
    -+		-r "alt refs/for/master/topic old-oid=$A new-oid=$B" \
    -+		-r "alt refs/for/master/topic refs/changes/25/125/1 old-oid=$B new-oid=$A forced-update"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/24/124/1" \
    ++		-r "option old-oid $ZERO_OID" \
    ++		-r "option new-oid $A" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/25/125/1" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report multiple alt, no alt-ref for the 2nd resp ($PROTOCOL)" '
    ++test_expect_success "proc-receive: multiple rewrite for one ref, no refname for the 1st rewrite ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/1 old-oid=<ZERO-OID> new-oid=<COMMIT-A>
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/25/125/1 old-oid=<COMMIT-B> new-oid=<COMMIT-A> forced-update
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/24/124/1
    ++	remote: proc-receive> option old-oid <ZERO-OID>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/25/125/1
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (ok and alt for the same ref, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
     +		-r "ok refs/for/master/topic" \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/1 new-oid=$B old-oid=$A"
    ++		-r "option refname refs/changes/24/124/1" \
    ++		-r "option old-oid $ZERO_OID" \
    ++		-r "option new-oid $A" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/25/125/1" \
    ++		-r "option old-oid $B" \
    ++		-r "option new-oid $A" \
    ++		-r "option forced-update"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report ok and alt for the same ref ($PROTOCOL)" '
    ++test_expect_success "proc-receive: multiple rewrites for one ref, no refname for the 2nd rewrite ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new)
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/1 new-oid=<COMMIT-B> old-oid=<COMMIT-A>
    ++	remote: proc-receive> option refname refs/changes/24/124/1
    ++	remote: proc-receive> option old-oid <ZERO-OID>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/25/125/1
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> option forced-update
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (multiple responses, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/changes/23/123/1" \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/2 old-oid=$A new-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/23/123/1" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/24/124/2" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report multiple response ($PROTOCOL)" '
    ++test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" '
     +	git -C workbench push origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/23/123/1
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/2 old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/23/123/1
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/24/124/2
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0036-report-multi-alt-for-one-ref.sh (new)
     +	test_cmp expect actual
     +'
     
    - ## t/t5411/test-0037-report-multi-alt-for-one-ref--porcelain.sh (new) ##
    + ## t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh (new) ##
     @@
    -+test_expect_success "setup proc-receive hook (multiple alt, no alt-ref for the 1st resp, $PROTOCOL)" '
    -+	write_script "$upstream/hooks/proc-receive" <<-EOF
    -+	printf >&2 "# proc-receive hook\n"
    -+	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic old-oid=$A new-oid=$B" \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/1 old-oid=$ZERO_OID new-oid=$A" \
    -+		-r "alt refs/for/master/topic refs/changes/25/125/1 old-oid=$A new-oid=$B"
    -+	EOF
    -+'
    -+
    -+# Refs of upstream : master(A)
    -+# Refs of workbench: master(A)  tags/v123
    -+# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report multiple alt, no alt-ref for the 1st resp (--porcelain, $PROTOCOL)" '
    -+	git -C workbench push --porcelain origin \
    -+		HEAD:refs/for/master/topic \
    -+		>out 2>&1 &&
    -+	make_user_friendly_and_stable_output <out >actual &&
    -+	cat >expect <<-EOF &&
    -+	remote: # pre-receive hook
    -+	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: # proc-receive hook
    -+	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/1 old-oid=<ZERO-OID> new-oid=<COMMIT-A>
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/25/125/1 old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: # post-receive hook
    -+	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	To <URL/of/upstream.git>
    -+	*    HEAD:refs/for/master/topic    [new reference]
    -+	Done
    -+	EOF
    -+	test_cmp expect actual &&
    -+	git -C "$upstream" show-ref >out &&
    -+	make_user_friendly_and_stable_output <out >actual &&
    -+	cat >expect <<-EOF &&
    -+	<COMMIT-A> refs/heads/master
    -+	EOF
    -+	test_cmp expect actual
    -+'
    -+
    -+test_expect_success "setup proc-receive hook (multiple alt, no alt-ref for the 2nd resp, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/1 old-oid=$ZERO_OID new-oid=$A" \
    -+		-r "alt refs/for/master/topic old-oid=$A new-oid=$B" \
    -+		-r "alt refs/for/master/topic refs/changes/25/125/1 old-oid=$B new-oid=$A forced-update"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/24/124/1" \
    ++		-r "option old-oid $ZERO_OID" \
    ++		-r "option new-oid $A" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/25/125/1" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report multiple alt, no alt-ref for the 2nd resp (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: multiple rewrite for one ref, no refname for the 1st rewrite ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0037-report-multi-alt-for-one-ref--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/1 old-oid=<ZERO-OID> new-oid=<COMMIT-A>
    -+	remote: proc-receive> alt refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/25/125/1 old-oid=<COMMIT-B> new-oid=<COMMIT-A> forced-update
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/24/124/1
    ++	remote: proc-receive> option old-oid <ZERO-OID>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/25/125/1
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0037-report-multi-alt-for-one-ref--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (ok and alt for the same ref, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
     +		-r "ok refs/for/master/topic" \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/1 new-oid=$B old-oid=$A"
    ++		-r "option refname refs/changes/24/124/1" \
    ++		-r "option old-oid $ZERO_OID" \
    ++		-r "option new-oid $A" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/25/125/1" \
    ++		-r "option old-oid $B" \
    ++		-r "option new-oid $A" \
    ++		-r "option forced-update"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report ok and alt for the same ref (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: multiple rewrites for one ref, no refname for the 2nd rewrite ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0037-report-multi-alt-for-one-ref--porcelain.sh (new)
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/1 new-oid=<COMMIT-B> old-oid=<COMMIT-A>
    ++	remote: proc-receive> option refname refs/changes/24/124/1
    ++	remote: proc-receive> option old-oid <ZERO-OID>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/25/125/1
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> option forced-update
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0037-report-multi-alt-for-one-ref--porcelain.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success "setup proc-receive hook (multiple responses, $PROTOCOL)" '
    ++test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" '
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "alt refs/for/master/topic refs/changes/23/123/1" \
    -+		-r "alt refs/for/master/topic refs/changes/24/124/2 old-oid=$A new-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/23/123/1" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/changes/24/124/2" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         :                       refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report multiple response (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		HEAD:refs/for/master/topic \
     +		>out 2>&1 &&
    @@ t/t5411/test-0037-report-multi-alt-for-one-ref--porcelain.sh (new)
     +	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: # proc-receive hook
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/23/123/1
    -+	remote: proc-receive> alt refs/for/master/topic refs/changes/24/124/2 old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/23/123/1
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/changes/24/124/2
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	To <URL/of/upstream.git>
    @@ t/t5411/test-0038-report-mixed-refs.sh (new)
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
     +		-r "ok refs/for/next/topic" \
    -+		-r "alt refs/for/master/topic refs/for/master/topic old-oid=$A new-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
    @@ t/t5411/test-0038-report-mixed-refs.sh (new)
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok refs/for/next/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
    @@ t/t5411/test-0038-report-mixed-refs.sh (new)
     +		git update-ref -d refs/heads/bar &&
     +		git update-ref -d refs/heads/baz
     +	)
    -+
     +'
     
      ## t/t5411/test-0039-report-mixed-refs--porcelain.sh (new) ##
    @@ t/t5411/test-0039-report-mixed-refs--porcelain.sh (new)
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
     +		-r "ok refs/for/next/topic" \
    -+		-r "alt refs/for/master/topic refs/for/master/topic old-oid=$A new-oid=$B"
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/for/master/topic" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B"
     +	EOF
     +'
     +
     +# Refs of upstream : master(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push         : (B)                   bar(A)  baz(A)  refs/for/next/topic(A)  foo(A)  refs/for/master/topic(A)
    -+test_expect_success "proc-receive: report update of mixed refs (--porcelain, $PROTOCOL)" '
    ++test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain origin \
     +		$B:refs/heads/master \
     +		HEAD:refs/heads/bar \
    @@ t/t5411/test-0039-report-mixed-refs--porcelain.sh (new)
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive> ok refs/for/next/topic
    -+	remote: proc-receive> alt refs/for/master/topic refs/for/master/topic old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/for/master/topic
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
     +	remote: # post-receive hook
     +	remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
     +	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
4:  d01004ff52 < -:  ---------- send-pack: extension for client-side status report
5:  583b5bdfcd < -:  ---------- receive-pack: feed extended_status to post-receive
-:  ---------- > 3:  267da25afd New capability "report-status-v2" for git-push
-:  ---------- > 4:  2cc92d9383 receive-pack: feed report options to post-receive
6:  860be91506 = 5:  47c5e59c9a refs.c: refactor to reuse ref_is_hidden()
7:  9489db75e6 ! 6:  37e041156f receive-pack: new config receive.procReceiveRefs
    @@ builtin/receive-pack.c: static void execute_commands(struct command *commands,
     +	if (proc_receive_refs.nr > 0) {
     +		struct strbuf refname_full = STRBUF_INIT;
     +		size_t prefix_len;
    ++
    ++		strbuf_addstr(&refname_full, get_git_namespace());
    ++		prefix_len = refname_full.len;
      
     -		/* TODO: replace the fixed prefix by looking up git config variables. */
     -		if (!strncmp(cmd->ref_name, "refs/for/", 9)) {
     -			cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED;
     -			run_proc_receive = 1;
    -+		strbuf_addstr(&refname_full, get_git_namespace());
    -+		prefix_len = refname_full.len;
    -+
     +		for (cmd = commands; cmd; cmd = cmd->next) {
     +			if (!should_process_cmd(cmd))
     +				continue;
    @@ t/t5411/test-0040-process-all-refs.sh (new)
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "ft refs/heads/master" \
    -+		-r "ft refs/heads/foo" \
    -+		-r "ft refs/heads/bar" \
    -+		-r "alt refs/for/master/topic refs/pull/123/head old-oid=$A new-oid=$B " \
    -+		-r "alt refs/for/next/topic refs/pull/124/head old-oid=$B new-oid=$A forced-update"
    ++		-r "ok refs/heads/master" \
    ++		-r "option fall-through" \
    ++		-r "ok refs/heads/foo" \
    ++		-r "option fall-through" \
    ++		-r "ok refs/heads/bar" \
    ++		-r "option fall-through" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B" \
    ++		-r "ok refs/for/next/topic" \
    ++		-r "option refname refs/pull/124/head" \
    ++		-r "option old-oid $B" \
    ++		-r "option new-oid $A" \
    ++		-r "option forced-update"
     +	EOF
     +'
     +
    @@ t/t5411/test-0040-process-all-refs.sh (new)
     +	remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
    -+	remote: proc-receive> ft refs/heads/master
    -+	remote: proc-receive> ft refs/heads/foo
    -+	remote: proc-receive> ft refs/heads/bar
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: proc-receive> alt refs/for/next/topic refs/pull/124/head old-oid=<COMMIT-B> new-oid=<COMMIT-A> forced-update
    ++	remote: proc-receive> ok refs/heads/master
    ++	remote: proc-receive> option fall-through
    ++	remote: proc-receive> ok refs/heads/foo
    ++	remote: proc-receive> option fall-through
    ++	remote: proc-receive> ok refs/heads/bar
    ++	remote: proc-receive> option fall-through
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
    ++	remote: proc-receive> ok refs/for/next/topic
    ++	remote: proc-receive> option refname refs/pull/124/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> option forced-update
     +	remote: # post-receive hook
     +	remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
     +	remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
    @@ t/t5411/test-0041-process-all-refs--porcelain.sh (new)
     +	write_script "$upstream/hooks/proc-receive" <<-EOF
     +	printf >&2 "# proc-receive hook\n"
     +	test-tool proc-receive -v \
    -+		-r "ft refs/heads/master" \
    -+		-r "ft refs/heads/foo" \
    -+		-r "ft refs/heads/bar" \
    -+		-r "alt refs/for/master/topic refs/pull/123/head old-oid=$A new-oid=$B " \
    -+		-r "alt refs/for/next/topic refs/pull/124/head old-oid=$B new-oid=$A forced-update"
    ++		-r "ok refs/heads/master" \
    ++		-r "option fall-through" \
    ++		-r "ok refs/heads/foo" \
    ++		-r "option fall-through" \
    ++		-r "ok refs/heads/bar" \
    ++		-r "option fall-through" \
    ++		-r "ok refs/for/master/topic" \
    ++		-r "option refname refs/pull/123/head" \
    ++		-r "option old-oid $A" \
    ++		-r "option new-oid $B" \
    ++		-r "ok refs/for/next/topic" \
    ++		-r "option refname refs/pull/124/head" \
    ++		-r "option old-oid $B" \
    ++		-r "option new-oid $A" \
    ++		-r "option forced-update"
     +	EOF
     +'
     +
     +# Refs of upstream : master(B)             foo(A)  bar(A))  baz(A)
     +# Refs of workbench: master(A)  tags/v123
     +# git push -f      : master(A)             (NULL)  (B)              refs/for/master/topic(A)  refs/for/next/topic(A)
    -+test_expect_success "proc-receive: process all refs (--porcelain) ($PROTOCOL)" '
    ++test_expect_success "proc-receive: process all refs ($PROTOCOL/porcelain)" '
     +	git -C workbench push --porcelain -f origin \
     +		HEAD:refs/heads/master \
     +		:refs/heads/foo \
    @@ t/t5411/test-0041-process-all-refs--porcelain.sh (new)
     +	remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
     +	remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
    -+	remote: proc-receive> ft refs/heads/master
    -+	remote: proc-receive> ft refs/heads/foo
    -+	remote: proc-receive> ft refs/heads/bar
    -+	remote: proc-receive> alt refs/for/master/topic refs/pull/123/head old-oid=<COMMIT-A> new-oid=<COMMIT-B>
    -+	remote: proc-receive> alt refs/for/next/topic refs/pull/124/head old-oid=<COMMIT-B> new-oid=<COMMIT-A> forced-update
    ++	remote: proc-receive> ok refs/heads/master
    ++	remote: proc-receive> option fall-through
    ++	remote: proc-receive> ok refs/heads/foo
    ++	remote: proc-receive> option fall-through
    ++	remote: proc-receive> ok refs/heads/bar
    ++	remote: proc-receive> option fall-through
    ++	remote: proc-receive> ok refs/for/master/topic
    ++	remote: proc-receive> option refname refs/pull/123/head
    ++	remote: proc-receive> option old-oid <COMMIT-A>
    ++	remote: proc-receive> option new-oid <COMMIT-B>
    ++	remote: proc-receive> ok refs/for/next/topic
    ++	remote: proc-receive> option refname refs/pull/124/head
    ++	remote: proc-receive> option old-oid <COMMIT-B>
    ++	remote: proc-receive> option new-oid <COMMIT-A>
    ++	remote: proc-receive> option forced-update
     +	remote: # post-receive hook
     +	remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
     +	remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
8:  187a723d71 ! 7:  5e08df63d2 doc: add documentation for the proc-receive hook
    @@ Documentation/githooks.txt: The default 'update' hook, when enabled--and with
      `hooks.allowunannotated` config option unset or set to false--prevents
      unannotated tags to be pushed.
      
    ++[[proc-receive]]
     +proc-receive
     +~~~~~~~~~~~~
     +
    @@ Documentation/githooks.txt: The default 'update' hook, when enabled--and with
     +    # NO, I reject it.
     +    H: PKT-LINE(ng <ref> <reason>)
     +    # Fall through, let 'receive-pack' to execute it.
    -+    H: PKT-LINE(ft <ref>)
    ++    H: PKT-LINE(ok <ref>)
    ++    H: PKT-LINE(option fall-through)
     +    # OK, but has an alternate reference.  The alternate reference name
    -+    # is given in the third parameter, and other status can be given in
    -+    # key-value pairs.
    -+    H: PKT-LINE(alt <ref> <alt-ref> old-oid=<old-oid> new-oid=<new-oid>
    -+                forced-update)
    ++    # and other status can be given in options
    ++    H: PKT-LINE(ok <ref>)
    ++    H: PKT-LINE(option refname <refname>)
    ++    H: PKT-LINE(option old-oid <old-oid>)
    ++    H: PKT-LINE(option new-oid <new-oid>)
    ++    H: PKT-LINE(option forced-update)
     +    H: ... ...
     +    H: flush-pkt
     +
     +Each command for the 'proc-receive' hook may point to a pseudo-reference
     +and always has a zero-old as its old-oid, while the 'proc-receive' hook
     +may update an alternate reference and the alternate reference may exist
    -+already with a non-zero old-oid.  For this case, this hook may return
    -+different OID and different reference name as extended status of the
    -+report line.
    ++already with a non-zero old-oid.  For this case, this hook will use
    ++"option" directives to report extended attributes for the reference given
    ++by the above "ok/ng" directive.
     +
     +The report of the commands of this hook should have the same order as
     +the input.  The exit status of the 'proc-receive' hook only determines

----

Jiang Xin (7):
  transport: not report a non-head push as a branch
  receive-pack: add new proc-receive hook
  New capability "report-status-v2" for git-push
  receive-pack: feed report options to post-receive
  refs.c: refactor to reuse ref_is_hidden()
  receive-pack: new config receive.procReceiveRefs
  doc: add documentation for the proc-receive hook

 Documentation/config/receive.txt              |  14 +
 Documentation/githooks.txt                    |  62 +++
 Makefile                                      |   1 +
 builtin/receive-pack.c                        | 459 ++++++++++++++++--
 builtin/send-pack.c                           |  21 +-
 refs.c                                        |  13 +-
 refs.h                                        |   1 +
 remote.c                                      |   7 +-
 remote.h                                      |  16 +-
 send-pack.c                                   |  96 +++-
 t/helper/test-proc-receive.c                  | 175 +++++++
 t/helper/test-tool.c                          |   1 +
 t/helper/test-tool.h                          |   1 +
 t/t5411-proc-receive-hook.sh                  | 106 ++++
 t/t5411/common-functions.sh                   |  56 +++
 t/t5411/test-0000-standard-git-push.sh        |  84 ++++
 .../test-0001-standard-git-push--porcelain.sh |  86 ++++
 t/t5411/test-0002-pre-receive-declined.sh     |  33 ++
 ...st-0003-pre-receive-declined--porcelain.sh |  34 ++
 t/t5411/test-0010-proc-receive-settings.sh    |   7 +
 t/t5411/test-0011-no-hook-error.sh            |  64 +++
 t/t5411/test-0012-no-hook-error--porcelain.sh |  66 +++
 t/t5411/test-0013-bad-protocol.sh             | 225 +++++++++
 t/t5411/test-0014-bad-protocol--porcelain.sh  | 160 ++++++
 t/t5411/test-0020-report-ng.sh                |  67 +++
 t/t5411/test-0021-report-ng--porcelain.sh     |  69 +++
 t/t5411/test-0022-report-unexpect-ref.sh      |  45 ++
 ...est-0023-report-unexpect-ref--porcelain.sh |  46 ++
 t/t5411/test-0024-report-unknown-ref.sh       |  34 ++
 ...test-0025-report-unknown-ref--porcelain.sh |  35 ++
 t/t5411/test-0026-push-options.sh             |  79 +++
 t/t5411/test-0027-push-options--porcelain.sh  |  82 ++++
 t/t5411/test-0030-report-ok.sh                |  35 ++
 t/t5411/test-0031-report-ok--porcelain.sh     |  36 ++
 t/t5411/test-0032-report-with-options.sh      | 256 ++++++++++
 ...est-0033-report-with-options--porcelain.sh | 265 ++++++++++
 t/t5411/test-0034-report-ft.sh                |  44 ++
 t/t5411/test-0035-report-ft--porcelain.sh     |  45 ++
 ...t-0036-report-multi-rewrite-for-one-ref.sh | 169 +++++++
 ...rt-multi-rewrite-for-one-ref--porcelain.sh | 172 +++++++
 t/t5411/test-0038-report-mixed-refs.sh        |  79 +++
 .../test-0039-report-mixed-refs--porcelain.sh |  81 ++++
 t/t5411/test-0040-process-all-refs.sh         | 113 +++++
 .../test-0041-process-all-refs--porcelain.sh  | 114 +++++
 t/t5516-fetch-push.sh                         |   2 +-
 transport-helper.c                            |  53 +-
 transport.c                                   | 121 +++--
 47 files changed, 3737 insertions(+), 93 deletions(-)
 create mode 100644 t/helper/test-proc-receive.c
 create mode 100755 t/t5411-proc-receive-hook.sh
 create mode 100644 t/t5411/common-functions.sh
 create mode 100644 t/t5411/test-0000-standard-git-push.sh
 create mode 100644 t/t5411/test-0001-standard-git-push--porcelain.sh
 create mode 100644 t/t5411/test-0002-pre-receive-declined.sh
 create mode 100644 t/t5411/test-0003-pre-receive-declined--porcelain.sh
 create mode 100644 t/t5411/test-0010-proc-receive-settings.sh
 create mode 100644 t/t5411/test-0011-no-hook-error.sh
 create mode 100644 t/t5411/test-0012-no-hook-error--porcelain.sh
 create mode 100644 t/t5411/test-0013-bad-protocol.sh
 create mode 100644 t/t5411/test-0014-bad-protocol--porcelain.sh
 create mode 100644 t/t5411/test-0020-report-ng.sh
 create mode 100644 t/t5411/test-0021-report-ng--porcelain.sh
 create mode 100644 t/t5411/test-0022-report-unexpect-ref.sh
 create mode 100644 t/t5411/test-0023-report-unexpect-ref--porcelain.sh
 create mode 100644 t/t5411/test-0024-report-unknown-ref.sh
 create mode 100644 t/t5411/test-0025-report-unknown-ref--porcelain.sh
 create mode 100644 t/t5411/test-0026-push-options.sh
 create mode 100644 t/t5411/test-0027-push-options--porcelain.sh
 create mode 100644 t/t5411/test-0030-report-ok.sh
 create mode 100644 t/t5411/test-0031-report-ok--porcelain.sh
 create mode 100644 t/t5411/test-0032-report-with-options.sh
 create mode 100644 t/t5411/test-0033-report-with-options--porcelain.sh
 create mode 100644 t/t5411/test-0034-report-ft.sh
 create mode 100644 t/t5411/test-0035-report-ft--porcelain.sh
 create mode 100644 t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
 create mode 100644 t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
 create mode 100644 t/t5411/test-0038-report-mixed-refs.sh
 create mode 100644 t/t5411/test-0039-report-mixed-refs--porcelain.sh
 create mode 100644 t/t5411/test-0040-process-all-refs.sh
 create mode 100644 t/t5411/test-0041-process-all-refs--porcelain.sh

-- 
2.26.1.120.g98702cf3e9


  reply	other threads:[~2020-05-05 14:41 UTC|newest]

Thread overview: 266+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-04 11:33 [PATCH 0/7] New execute-commands hook for centralized workflow Jiang Xin
2020-03-04 11:33 ` [PATCH 1/7] receive-pack: new external execute-commands hook Jiang Xin
2020-03-04 11:33 ` [PATCH 2/7] receive-pack: feed all commands to post-receive Jiang Xin
2020-03-04 11:33 ` [PATCH 3/7] receive-pack: try `execute-commands --pre-receive` Jiang Xin
2020-03-04 11:33 ` [PATCH 4/7] receive-pack: read env from execute-commands output Jiang Xin
2020-03-04 11:33 ` [PATCH 5/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-03-04 11:33 ` [PATCH 6/7] receive-pack: new config receive.executeCommandsHookRefs Jiang Xin
2020-03-04 11:33 ` [PATCH 7/7] hook: add document and example for "execute-commands" hook Jiang Xin
2020-03-04 20:39 ` [PATCH 0/7] New execute-commands hook for centralized workflow Junio C Hamano
2020-03-05 16:51   ` Jiang Xin
2020-03-08 14:56     ` [PATCH v2 0/5] New proc-receive " Jiang Xin
2020-03-08 14:56     ` [PATCH v2 1/5] receive-pack: add new proc-receive hook Jiang Xin
2020-03-09 17:12       ` Junio C Hamano
2020-03-10  6:03         ` Jiang Xin
2020-03-13 12:23           ` [PATCH v3 0/4] New proc-receive hook for centralized workflow Jiang Xin
2020-03-22 13:18             ` [PATCH v4 0/5] " Jiang Xin
2020-03-25  5:19               ` Junio C Hamano
2020-03-22 13:18             ` [PATCH v4 1/5] transport: not report a non-head push as a branch Jiang Xin
2020-03-25  6:04               ` Junio C Hamano
2020-03-22 13:18             ` [PATCH v4 2/5] receive-pack: add new proc-receive hook Jiang Xin
2020-03-25 14:36               ` [PATCH 0/3] Never report references we not push Jiang Xin
2020-03-29 14:33                 ` [PATCH v2 0/4] " Jiang Xin
2020-03-29 14:35                   ` Jiang Xin
2020-04-16 16:24                   ` [PATCH v3 0/5] fix git-push porcelain output and atomic report issue Jiang Xin
2020-04-17  9:45                     ` [PATCH v4 " Jiang Xin
2020-04-17  9:45                     ` [PATCH v4 1/5] send-pack: fix inconsistent porcelain output Jiang Xin
2020-04-17 19:51                       ` Junio C Hamano
2020-04-17  9:45                     ` [PATCH v4 2/5] t5543: never report what we do not push Jiang Xin
2020-04-17  9:45                     ` [PATCH v4 3/5] send-pack: mark failure of atomic push properly Jiang Xin
2020-04-17  9:45                     ` [PATCH v4 4/5] transport-helper: mark failure for atomic push Jiang Xin
2020-04-17  9:45                     ` [PATCH v4 5/5] transport-helper: new method reject_atomic_push() Jiang Xin
2020-04-16 16:24                   ` [PATCH v3 1/5] send-pack: fix inconsistent porcelain output Jiang Xin
2020-04-16 16:24                   ` [PATCH v3 2/5] t5543: never report what we do not push Jiang Xin
2020-04-16 16:24                   ` [PATCH v3 3/5] send-pack: mark failure of atomic push properly Jiang Xin
2020-04-16 16:24                   ` [PATCH v3 4/5] transport-helper: mark failure for atomic push Jiang Xin
2020-04-16 16:24                   ` [PATCH v3 5/5] transport-helper: new method reject_atomic_push() Jiang Xin
2020-03-29 14:33                 ` [PATCH v2 1/4] t5543: never report what we do not push Jiang Xin
2020-03-29 14:33                 ` [PATCH v2 2/4] send-pack: mark failure of atomic push properly Jiang Xin
2020-03-29 14:33                 ` [PATCH v2 3/4] transport-helper: mark failure for atomic push Jiang Xin
2020-03-29 14:33                 ` [PATCH v2 4/4] transport-helper: new method reject_atomic_push() Jiang Xin
2020-03-25 14:36               ` [PATCH 1/3] t5543: never report what we do not push Jiang Xin
2020-03-25 15:05                 ` Junio C Hamano
2020-03-26  2:25                   ` Jiang Xin
2020-03-25 14:36               ` [PATCH 2/3] send-pack: mark failure of atomic push properly Jiang Xin
2020-03-25 15:15                 ` Junio C Hamano
2020-03-25 14:36               ` [PATCH 3/3] transport-helper: enforce atomic in push_refs_with_push Jiang Xin
2020-03-25 15:32                 ` Junio C Hamano
2020-03-22 13:18             ` [PATCH v4 3/5] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-03-22 13:18             ` [PATCH v4 4/5] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-03-22 13:18             ` [PATCH v4 5/5] receive-pack: refactor report for proc-receive Jiang Xin
2020-03-13 12:23           ` [PATCH v3 1/4] receive-pack: add new proc-receive hook Jiang Xin
2020-03-13 12:23           ` [PATCH v3 2/4] receive-pack: refactor report for proc-receive Jiang Xin
2020-03-13 12:23           ` [PATCH v3 3/4] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-03-13 12:23           ` [PATCH v3 4/4] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-03-08 14:56     ` [PATCH v2 2/5] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-03-08 15:38     ` [PATCH v2 3/5] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-03-08 15:38     ` [PATCH v2 4/5] receive-pack: read env from proc-receive output Jiang Xin
2020-03-08 15:38     ` [PATCH v2 5/5] hook: add document and example for "proc-receive" hook Jiang Xin
2020-03-30 16:57 ` [PATCH v5 0/6] New proc-receive hook for centralized workflow Jiang Xin
2020-03-30 16:57 ` [PATCH v5 1/6] transport: not report a non-head push as a branch Jiang Xin
2020-03-30 16:57 ` [PATCH v5 2/6] receive-pack: add new proc-receive hook Jiang Xin
2020-03-31  0:19   ` Junio C Hamano
2020-03-31  0:21   ` Junio C Hamano
2020-03-30 16:57 ` [PATCH v5 3/6] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-03-30 16:57 ` [PATCH v5 4/6] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-03-30 16:57 ` [PATCH v5 5/6] receive-pack: refactor report for proc-receive Jiang Xin
2020-03-30 16:57 ` [PATCH v5 6/6] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-02 16:35 ` [PATCH v6 0/7] New proc-receive hook for centralized workflow Jiang Xin
2020-04-02 18:26   ` Junio C Hamano
2020-04-03 16:08     ` [PATCH v7 " Jiang Xin
2020-04-04 13:43       ` [PATCH v8 " Jiang Xin
2020-04-07 12:08         ` [PATCH v9 0/6] " Jiang Xin
2020-04-12 13:30           ` [PATCH v10 0/8] " Jiang Xin
2020-04-13 16:48             ` [PATCH v11 0/7] " Jiang Xin
2020-04-13 16:48             ` [PATCH v11 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-04-13 16:48             ` [PATCH v11 2/7] connect: export parse_feature_value() Jiang Xin
2020-04-13 16:48             ` [PATCH v11 3/7] receive-pack: add new proc-receive hook Jiang Xin
2020-04-13 16:48             ` [PATCH v11 4/7] send-pack: extension for client-side status report Jiang Xin
2020-04-13 16:48             ` [PATCH v11 5/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-13 16:48             ` [PATCH v11 6/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-13 16:48             ` [PATCH v11 7/7] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-12 13:30           ` [PATCH v10 1/8] transport: not report a non-head push as a branch Jiang Xin
2020-04-12 20:26             ` Junio C Hamano
2020-04-13 11:15               ` Jiang Xin
2020-04-12 13:30           ` [PATCH v10 2/8] receive-pack: add new proc-receive hook Jiang Xin
2020-04-12 21:30             ` Junio C Hamano
2020-04-13 10:58               ` Jiang Xin
2020-04-13 21:50                 ` Junio C Hamano
2020-04-14 12:32                   ` [PATCH v12 0/7] New proc-receive hook for centralized workflow Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 0/8] " Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 1/8] transport: not report a non-head push as a branch Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 2/8] connect: export parse_feature_value() Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 3/8] receive-pack: add new proc-receive hook Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 4/8] send-pack: extension for client-side status report Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 5/8] receive-pack: feed extended_status to post-receive Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 6/8] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 7/8] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-18 16:03                     ` [PATCH v13 8/8] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-14 12:32                   ` [PATCH v12 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-04-14 12:32                   ` [PATCH v12 2/7] connect: export parse_feature_value() Jiang Xin
2020-04-14 12:32                   ` [PATCH v12 3/7] receive-pack: add new proc-receive hook Jiang Xin
2020-04-15 15:48                     ` Junio C Hamano
2020-04-15 15:55                       ` Jiang Xin
2020-04-15 18:34                         ` Junio C Hamano
2020-04-27 17:00                           ` Jiang Xin
2020-04-29  7:56                             ` Jeff King
2020-04-30 15:33                               ` Jiang Xin
2020-05-05 14:41                                 ` Jiang Xin [this message]
2020-05-06 23:14                                   ` [PATCH v14 0/7] New proc-receive hook for centralized workflow Junio C Hamano
2020-05-07  1:37                                     ` Jiang Xin
2020-05-07 11:18                                       ` Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 " Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 00/11] " Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 00/10] " Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 " Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 " Jiang Xin
2020-08-27 19:57                                               ` Junio C Hamano
2020-08-27 15:45                                             ` [PATCH v19 01/10] transport: not report a non-head push as a branch Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 02/10] t5411: add basic test cases for proc-receive hook Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 03/10] receive-pack: add new " Jiang Xin
2020-11-04 22:15                                               ` Johannes Schindelin
2020-11-04 22:58                                                 ` Johannes Schindelin
2020-11-05 14:54                                                 ` Jiang Xin
2020-11-05 15:23                                                   ` [RFC PATCH] t5411: fix broken pipe write error on proc-receive Jiang Xin
2020-11-05 19:14                                                     ` Junio C Hamano
2020-11-07  2:57                                                       ` [PATCH] t5411: consistent result for proc-receive broken test Jiang Xin
2020-11-09  7:29                                                         ` Jiang Xin
2020-11-09 10:58                                                           ` [PATCH v2] " Jiang Xin
2020-11-09 20:59                                                             ` Junio C Hamano
2020-11-09 23:12                                                               ` Jeff King
2020-11-09 23:22                                                                 ` Junio C Hamano
2020-11-10  0:03                                                                   ` Jeff King
2020-11-10 11:49                                                                 ` Jiang Xin
2020-11-10 12:01                                                                   ` [PATCH v3 1/2] t5411: refactor make_user_friendly_and_stable_output Jiang Xin
2020-11-10 20:51                                                                     ` Junio C Hamano
2020-11-11 11:08                                                                       ` Jiang Xin
2020-11-10 12:01                                                                   ` [PATCH v3 2/2] receive-pack: gently write messages to proc-receive Jiang Xin
2020-11-10 21:52                                                                     ` Jeff King
2020-11-11 11:03                                                                       ` Jiang Xin
2020-11-10 21:00                                                                   ` [PATCH v2] t5411: consistent result for proc-receive broken test Junio C Hamano
2020-11-10 21:13                                                                     ` Junio C Hamano
2020-11-11 11:31                                                                   ` [PATCH v4 0/3] jx/t5411-flake-fix Jiang Xin
2020-11-11 11:32                                                                   ` [PATCH v4 1/3] t5411: new helper filter_out_user_friendly_and_stable_output Jiang Xin
2020-11-11 11:32                                                                   ` [PATCH v4 2/3] receive-pack: gently write messages to proc-receive Jiang Xin
2020-11-11 11:32                                                                   ` [PATCH v4 3/3] receive-pack: use default version 0 for proc-receive Jiang Xin
2020-11-10 11:44                                                               ` [PATCH v2] t5411: consistent result for proc-receive broken test Jiang Xin
2020-11-05 18:39                                                   ` [PATCH v19 03/10] receive-pack: add new proc-receive hook Junio C Hamano
2021-01-17 22:21                                               ` SZEDER Gábor
2021-01-18  8:24                                                 ` Jiang Xin
2021-01-20 12:28                                                   ` SZEDER Gábor
2021-01-21  2:21                                                     ` Jiang Xin
2021-01-21  6:12                                                       ` SZEDER Gábor
2021-01-18 13:30                                                 ` [PATCH 1/2] t5411: remove file after use to prevent overwriting Jiang Xin
2021-01-18 18:21                                                   ` Johannes Sixt
2021-01-19  0:48                                                     ` Jiang Xin
2021-01-19 10:24                                                     ` [PATCH v2 0/2] t5411 out file overwrite fix Jiang Xin
2021-01-19 10:24                                                     ` [PATCH v2 1/2] t5411: use different out file to prevent overwriting Jiang Xin
2021-01-20 12:49                                                       ` SZEDER Gábor
2021-01-21  1:59                                                         ` Jiang Xin
2021-01-21  2:53                                                         ` [PATCH v3 0/2] use unique out file in t5411 Jiang Xin
2021-02-11 21:52                                                           ` Junio C Hamano
2021-02-13 15:13                                                             ` Jiang Xin
2021-01-21  2:53                                                         ` [PATCH v3 1/2] t5411: use different out file to prevent overwriting Jiang Xin
2021-01-21  2:53                                                         ` [PATCH v3 2/2] t5411: refactor check of refs using test_cmp_refs Jiang Xin
2021-01-19 10:24                                                     ` [PATCH v2 " Jiang Xin
2021-01-18 13:30                                                 ` [PATCH " Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 04/10] receive-pack: feed report options to post-receive Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 05/10] New capability "report-status-v2" for git-push Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 06/10] doc: add document for capability report-status-v2 Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 07/10] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 08/10] t5411: test updates of remote-tracking branches Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 09/10] transport: parse report options for tracking refs Jiang Xin
2020-08-27 15:45                                             ` [PATCH v19 10/10] doc: add documentation for the proc-receive hook Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 01/10] transport: not report a non-head push as a branch Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 02/10] t5411: add basic test cases for proc-receive hook Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 03/10] receive-pack: add new " Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 04/10] receive-pack: feed report options to post-receive Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 05/10] New capability "report-status-v2" for git-push Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 06/10] doc: add document for capability report-status-v2 Jiang Xin
2020-08-24 17:41                                           ` [PATCH v18 07/10] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-08-24 17:42                                           ` [PATCH v18 08/10] t5411: test updates of remote-tracking branches Jiang Xin
2020-08-24 17:42                                           ` [PATCH v18 09/10] transport: parse report options for tracking refs Jiang Xin
2020-08-24 17:42                                           ` [PATCH v18 10/10] doc: add documentation for the proc-receive hook Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 01/10] transport: not report a non-head push as a branch Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 02/10] t5411: add basic test cases for proc-receive hook Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 03/10] receive-pack: add new " Jiang Xin
2020-08-17 20:53                                           ` Junio C Hamano
2020-08-15 17:17                                         ` [PATCH v17 04/10] New capability "report-status-v2" for git-push Jiang Xin
2020-08-17 21:12                                           ` Junio C Hamano
2020-08-15 17:17                                         ` [PATCH v17 05/10] doc: add document for capability report-status-v2 Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 06/10] receive-pack: feed report options to post-receive Jiang Xin
2020-08-17 21:15                                           ` Junio C Hamano
2020-08-15 17:17                                         ` [PATCH v17 07/10] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-08-17 21:25                                           ` Junio C Hamano
2020-08-15 17:17                                         ` [PATCH v17 08/10] t5411: test updates of remote-tracking branches Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 09/10] transport: parse report options for tracking refs Jiang Xin
2020-08-15 17:17                                         ` [PATCH v17 10/10] doc: add documentation for the proc-receive hook Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 01/11] transport: not report a non-head push as a branch Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 02/11] t5411: add basic test cases for proc-receive hook Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 03/11] receive-pack: add new " Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 04/11] New capability "report-status-v2" for git-push Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 05/11] doc: add document for capability report-status-v2 Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 06/11] receive-pack: feed report options to post-receive Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 07/11] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 08/11] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 09/11] t5411: test updates of remote-tracking branches Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 10/11] transport: parse report options for tracking refs Jiang Xin
2020-05-18  9:40                                       ` [PATCH v16 11/11] doc: add documentation for the proc-receive hook Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 2/7] receive-pack: add new proc-receive hook Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 3/7] New capability "report-status-v2" for git-push Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 4/7] receive-pack: feed report options to post-receive Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 5/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 6/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-05-07 16:10                                     ` [PATCH v15 7/7] doc: add documentation for the proc-receive hook Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 2/7] receive-pack: add new proc-receive hook Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 3/7] New capability "report-status-v2" for git-push Jiang Xin
2020-05-05 15:25                                   ` [PATCH v14 8/7] fixup! " Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 4/7] receive-pack: feed report options to post-receive Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 5/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 6/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-05-05 14:41                                 ` [PATCH v14 7/7] doc: add documentation for the proc-receive hook Jiang Xin
2020-05-07 17:27                                 ` [PATCH v12 3/7] receive-pack: add new " Jeff King
2020-04-14 12:32                   ` [PATCH v12 4/7] send-pack: extension for client-side status report Jiang Xin
2020-04-15 20:36                     ` Junio C Hamano
2020-04-14 12:32                   ` [PATCH v12 5/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-14 12:32                   ` [PATCH v12 6/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-14 12:32                   ` [PATCH v12 7/7] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-12 13:30           ` [PATCH v10 3/8] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-12 21:38             ` Junio C Hamano
2020-04-13 11:16               ` Jiang Xin
2020-04-12 13:30           ` [PATCH v10 4/8] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-12 21:46             ` Junio C Hamano
2020-04-13 11:16               ` Jiang Xin
2020-04-12 13:30           ` [PATCH v10 5/8] connect: export parse_feature_value() Jiang Xin
2020-04-12 13:30           ` [PATCH v10 6/8] receive-pack: extension for server-side report Jiang Xin
2020-04-12 13:30           ` [PATCH v10 7/8] send-pack: extension for client-side status report Jiang Xin
2020-04-12 13:30           ` [PATCH v10 8/8] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-07 12:08         ` [PATCH v9 1/6] transport: not report a non-head push as a branch Jiang Xin
2020-04-07 12:08         ` [PATCH v9 2/6] receive-pack: add new proc-receive hook Jiang Xin
2020-04-07 12:08         ` [PATCH v9 3/6] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-07 12:08         ` [PATCH v9 4/6] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-07 12:08         ` [PATCH v9 5/6] receive-pack: refactor report for proc-receive Jiang Xin
2020-04-07 12:08         ` [PATCH v9 6/6] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-04 13:43       ` [PATCH v8 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-04-04 13:43       ` [PATCH v8 2/7] receive-pack: add new proc-receive hook Jiang Xin
2020-04-04 13:43       ` [PATCH v8 3/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-04 13:43       ` [PATCH v8 4/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-04 13:43       ` [PATCH v8 5/7] receive-pack: refactor report for proc-receive Jiang Xin
2020-04-04 13:43       ` [PATCH v8 6/7] t5412: test the proc-receive hook on HTTP protocol Jiang Xin
2020-04-04 13:43       ` [PATCH v8 7/7] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-03 16:08     ` [PATCH v7 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-04-03 16:08     ` [PATCH v7 2/7] receive-pack: add new proc-receive hook Jiang Xin
2020-04-03 16:08     ` [PATCH v7 3/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-03 16:08     ` [PATCH v7 4/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-03 16:08     ` [PATCH v7 5/7] receive-pack: refactor report for proc-receive Jiang Xin
2020-04-03 16:08     ` [PATCH v7 6/7] t5412: test proc-receive hook on HTTP protocol Jiang Xin
2020-04-03 16:08     ` [PATCH v7 7/7] doc: add documentation for the proc-receive hook Jiang Xin
2020-04-02 16:35 ` [PATCH v6 1/7] transport: not report a non-head push as a branch Jiang Xin
2020-04-02 16:35 ` [PATCH v6 2/7] receive-pack: add new proc-receive hook Jiang Xin
2020-04-02 16:35 ` [PATCH v6 3/7] refs.c: refactor to reuse ref_is_hidden() Jiang Xin
2020-04-02 16:35 ` [PATCH v6 4/7] receive-pack: new config receive.procReceiveRefs Jiang Xin
2020-04-02 16:35 ` [PATCH v6 5/7] receive-pack: refactor report for proc-receive Jiang Xin
2020-04-02 16:35 ` [PATCH v6 6/7] t5412: test proc-receive hook on HTTP protocol Jiang Xin
2020-04-02 16:35 ` [PATCH v6 7/7] doc: add documentation for the proc-receive hook Jiang Xin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200505144131.30048-1-worldhello.net@gmail.com \
    --to=worldhello.net@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=peff@peff.net \
    --cc=zhiyou.jx@alibaba-inc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.