git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v14 0/7] New proc-receive hook for centralized workflow

From
Jiang Xin <worldhello.net@gmail.com>
Date
May 5, 2020, 14:41 UTC
Message-ID
<20200505144131.30048-1-worldhello.net@gmail.com>
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
Previous: Jiang XinNext: Junio C Hamano
Message 121 of 266 in “New execute-commands hook for centralized workflow”
  1. 0/7 New execute-commands hook for centralized workflowJiang Xin, Mar 4, 2020
  2. 2/7 receive-pack: feed all commands to post-receiveJiang Xin, Mar 4, 2020
  3. 1/7 receive-pack: new external execute-commands hookJiang Xin, Mar 4, 2020
  4. 3/7 receive-pack: try `execute-commands --pre-receive`Jiang Xin, Mar 4, 2020
  5. 4/7 receive-pack: read env from execute-commands outputJiang Xin, Mar 4, 2020
  6. 5/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Mar 4, 2020
  7. 6/7 receive-pack: new config receive.executeCommandsHookRefsJiang Xin, Mar 4, 2020
  8. 7/7 hook: add document and example for "execute-commands" hookJiang Xin, Mar 4, 2020
  9. Junio C HamanoMar 4, 2020
  10. Jiang XinMar 5, 2020
  11. 0/5 New proc-receive hook for centralized workflowJiang Xin, Mar 8, 2020
  12. 1/5 receive-pack: add new proc-receive hookJiang Xin, Mar 8, 2020
  13. Junio C HamanoMar 9, 2020
  14. Jiang XinMar 10, 2020
  15. 0/4 New proc-receive hook for centralized workflowJiang Xin, Mar 13, 2020
  16. 0/5 New proc-receive hook for centralized workflowJiang Xin, Mar 22, 2020
  17. Junio C HamanoMar 25, 2020
  18. 1/5 transport: not report a non-head push as a branchJiang Xin, Mar 22, 2020
  19. Junio C HamanoMar 25, 2020
  20. 3/5 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Mar 22, 2020
  21. 4/5 receive-pack: new config receive.procReceiveRefsJiang Xin, Mar 22, 2020
  22. 2/5 receive-pack: add new proc-receive hookJiang Xin, Mar 22, 2020
  23. 1/3 t5543: never report what we do not pushJiang Xin, Mar 25, 2020
  24. Junio C HamanoMar 25, 2020
  25. Jiang XinMar 26, 2020
  26. 0/3 Never report references we not pushJiang Xin, Mar 25, 2020
  27. 0/4 Never report references we not pushJiang Xin, Mar 29, 2020
  28. Jiang XinMar 29, 2020
  29. 1/5 send-pack: fix inconsistent porcelain outputJiang Xin, Apr 16, 2020
  30. 0/5 fix git-push porcelain output and atomic report issueJiang Xin, Apr 16, 2020
  31. 0/5 fix git-push porcelain output and atomic report issueJiang Xin, Apr 17, 2020
  32. 2/5 t5543: never report what we do not pushJiang Xin, Apr 17, 2020
  33. 1/5 send-pack: fix inconsistent porcelain outputJiang Xin, Apr 17, 2020
  34. Junio C HamanoApr 17, 2020
  35. 4/5 transport-helper: mark failure for atomic pushJiang Xin, Apr 17, 2020
  36. 3/5 send-pack: mark failure of atomic push properlyJiang Xin, Apr 17, 2020
  37. 5/5 transport-helper: new method reject_atomic_push()Jiang Xin, Apr 17, 2020
  38. 2/5 t5543: never report what we do not pushJiang Xin, Apr 16, 2020
  39. 3/5 send-pack: mark failure of atomic push properlyJiang Xin, Apr 16, 2020
  40. 4/5 transport-helper: mark failure for atomic pushJiang Xin, Apr 16, 2020
  41. 5/5 transport-helper: new method reject_atomic_push()Jiang Xin, Apr 16, 2020
  42. 1/4 t5543: never report what we do not pushJiang Xin, Mar 29, 2020
  43. 2/4 send-pack: mark failure of atomic push properlyJiang Xin, Mar 29, 2020
  44. 4/4 transport-helper: new method reject_atomic_push()Jiang Xin, Mar 29, 2020
  45. 3/4 transport-helper: mark failure for atomic pushJiang Xin, Mar 29, 2020
  46. 2/3 send-pack: mark failure of atomic push properlyJiang Xin, Mar 25, 2020
  47. Junio C HamanoMar 25, 2020
  48. 3/3 transport-helper: enforce atomic in push_refs_with_pushJiang Xin, Mar 25, 2020
  49. Junio C HamanoMar 25, 2020
  50. 5/5 receive-pack: refactor report for proc-receiveJiang Xin, Mar 22, 2020
  51. 1/4 receive-pack: add new proc-receive hookJiang Xin, Mar 13, 2020
  52. 2/4 receive-pack: refactor report for proc-receiveJiang Xin, Mar 13, 2020
  53. 4/4 receive-pack: new config receive.procReceiveRefsJiang Xin, Mar 13, 2020
  54. 3/4 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Mar 13, 2020
  55. 2/5 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Mar 8, 2020
  56. 3/5 receive-pack: new config receive.procReceiveRefsJiang Xin, Mar 8, 2020
  57. 4/5 receive-pack: read env from proc-receive outputJiang Xin, Mar 8, 2020
  58. 5/5 hook: add document and example for "proc-receive" hookJiang Xin, Mar 8, 2020
  59. 1/6 transport: not report a non-head push as a branchJiang Xin, Mar 30, 2020
  60. 0/6 New proc-receive hook for centralized workflowJiang Xin, Mar 30, 2020
  61. 4/6 receive-pack: new config receive.procReceiveRefsJiang Xin, Mar 30, 2020
  62. 5/6 receive-pack: refactor report for proc-receiveJiang Xin, Mar 30, 2020
  63. 2/6 receive-pack: add new proc-receive hookJiang Xin, Mar 30, 2020
  64. Junio C HamanoMar 31, 2020
  65. Junio C HamanoMar 31, 2020
  66. 6/6 doc: add documentation for the proc-receive hookJiang Xin, Mar 30, 2020
  67. 3/6 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Mar 30, 2020
  68. 3/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 2, 2020
  69. 1/7 transport: not report a non-head push as a branchJiang Xin, Apr 2, 2020
  70. 4/7 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 2, 2020
  71. 2/7 receive-pack: add new proc-receive hookJiang Xin, Apr 2, 2020
  72. 0/7 New proc-receive hook for centralized workflowJiang Xin, Apr 2, 2020
  73. Junio C HamanoApr 2, 2020
  74. 1/7 transport: not report a non-head push as a branchJiang Xin, Apr 3, 2020
  75. 3/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 3, 2020
  76. 2/7 receive-pack: add new proc-receive hookJiang Xin, Apr 3, 2020
  77. 5/7 receive-pack: refactor report for proc-receiveJiang Xin, Apr 3, 2020
  78. 4/7 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 3, 2020
  79. 0/7 New proc-receive hook for centralized workflowJiang Xin, Apr 3, 2020
  80. 0/7 New proc-receive hook for centralized workflowJiang Xin, Apr 4, 2020
  81. 0/6 New proc-receive hook for centralized workflowJiang Xin, Apr 7, 2020
  82. 1/8 transport: not report a non-head push as a branchJiang Xin, Apr 12, 2020
  83. Junio C HamanoApr 12, 2020
  84. Jiang XinApr 13, 2020
  85. 0/8 New proc-receive hook for centralized workflowJiang Xin, Apr 12, 2020
  86. 0/7 New proc-receive hook for centralized workflowJiang Xin, Apr 13, 2020
  87. 1/7 transport: not report a non-head push as a branchJiang Xin, Apr 13, 2020
  88. 3/7 receive-pack: add new proc-receive hookJiang Xin, Apr 13, 2020
  89. 6/7 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 13, 2020
  90. 5/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 13, 2020
  91. 7/7 doc: add documentation for the proc-receive hookJiang Xin, Apr 13, 2020
  92. 2/7 connect: export parse_feature_value()Jiang Xin, Apr 13, 2020
  93. 4/7 send-pack: extension for client-side status reportJiang Xin, Apr 13, 2020
  94. 3/8 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 12, 2020
  95. Junio C HamanoApr 12, 2020
  96. Jiang XinApr 13, 2020
  97. 2/8 receive-pack: add new proc-receive hookJiang Xin, Apr 12, 2020
  98. Junio C HamanoApr 12, 2020
  99. Jiang XinApr 13, 2020
  100. Junio C HamanoApr 13, 2020
  101. 1/7 transport: not report a non-head push as a branchJiang Xin, Apr 14, 2020
  102. 0/7 New proc-receive hook for centralized workflowJiang Xin, Apr 14, 2020
  103. 1/8 transport: not report a non-head push as a branchJiang Xin, Apr 18, 2020
  104. 0/8 New proc-receive hook for centralized workflowJiang Xin, Apr 18, 2020
  105. 2/8 connect: export parse_feature_value()Jiang Xin, Apr 18, 2020
  106. 4/8 send-pack: extension for client-side status reportJiang Xin, Apr 18, 2020
  107. 8/8 doc: add documentation for the proc-receive hookJiang Xin, Apr 18, 2020
  108. 6/8 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 18, 2020
  109. 7/8 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 18, 2020
  110. 5/8 receive-pack: feed extended_status to post-receiveJiang Xin, Apr 18, 2020
  111. 3/8 receive-pack: add new proc-receive hookJiang Xin, Apr 18, 2020
  112. 2/7 connect: export parse_feature_value()Jiang Xin, Apr 14, 2020
  113. 3/7 receive-pack: add new proc-receive hookJiang Xin, Apr 14, 2020
  114. Junio C HamanoApr 15, 2020
  115. Jiang XinApr 15, 2020
  116. Junio C HamanoApr 15, 2020
  117. Jiang XinApr 27, 2020
  118. Jeff KingApr 29, 2020
  119. Jiang XinApr 30, 2020
  120. 1/7 transport: not report a non-head push as a branchJiang Xin, May 5, 2020
  121. 0/7 New proc-receive hook for centralized workflowJiang Xin, May 5, 2020
  122. Junio C HamanoMay 6, 2020
  123. Jiang XinMay 7, 2020
  124. Jiang XinMay 7, 2020
  125. 1/7 transport: not report a non-head push as a branchJiang Xin, May 7, 2020
  126. 0/7 New proc-receive hook for centralized workflowJiang Xin, May 7, 2020
  127. 01/11 transport: not report a non-head push as a branchJiang Xin, May 18, 2020
  128. 00/11 New proc-receive hook for centralized workflowJiang Xin, May 18, 2020
  129. 08/10 t5411: test updates of remote-tracking branchesJiang Xin, Aug 15, 2020
  130. 01/10 transport: not report a non-head push as a branchJiang Xin, Aug 15, 2020
  131. 10/10 doc: add documentation for the proc-receive hookJiang Xin, Aug 15, 2020
  132. 06/10 receive-pack: feed report options to post-receiveJiang Xin, Aug 15, 2020
  133. Junio C HamanoAug 17, 2020
  134. 03/10 receive-pack: add new proc-receive hookJiang Xin, Aug 15, 2020
  135. Junio C HamanoAug 17, 2020
  136. 07/10 receive-pack: new config receive.procReceiveRefsJiang Xin, Aug 15, 2020
  137. Junio C HamanoAug 17, 2020
  138. 05/10 doc: add document for capability report-status-v2Jiang Xin, Aug 15, 2020
  139. 02/10 t5411: add basic test cases for proc-receive hookJiang Xin, Aug 15, 2020
  140. 04/10 New capability "report-status-v2" for git-pushJiang Xin, Aug 15, 2020
  141. Junio C HamanoAug 17, 2020
  142. 09/10 transport: parse report options for tracking refsJiang Xin, Aug 15, 2020
  143. 00/10 New proc-receive hook for centralized workflowJiang Xin, Aug 15, 2020
  144. 00/10 New proc-receive hook for centralized workflowJiang Xin, Aug 24, 2020
  145. 01/10 transport: not report a non-head push as a branchJiang Xin, Aug 27, 2020
  146. 00/10 New proc-receive hook for centralized workflowJiang Xin, Aug 27, 2020
  147. Junio C HamanoAug 27, 2020
  148. 02/10 t5411: add basic test cases for proc-receive hookJiang Xin, Aug 27, 2020
  149. 04/10 receive-pack: feed report options to post-receiveJiang Xin, Aug 27, 2020
  150. 07/10 receive-pack: new config receive.procReceiveRefsJiang Xin, Aug 27, 2020
  151. 03/10 receive-pack: add new proc-receive hookJiang Xin, Aug 27, 2020
  152. Johannes SchindelinNov 4, 2020
  153. Johannes SchindelinNov 4, 2020
  154. Jiang XinNov 5, 2020
  155. t5411: fix broken pipe write error on proc-receiveJiang Xin, Nov 5, 2020
  156. Junio C HamanoNov 5, 2020
  157. t5411: consistent result for proc-receive broken testJiang Xin, Nov 7, 2020
  158. Jiang XinNov 9, 2020
  159. t5411: consistent result for proc-receive broken testJiang Xin, Nov 9, 2020
  160. Junio C HamanoNov 9, 2020
  161. Jeff KingNov 9, 2020
  162. Junio C HamanoNov 9, 2020
  163. Jeff KingNov 10, 2020
  164. Jiang XinNov 10, 2020
  165. 1/2 t5411: refactor make_user_friendly_and_stable_outputJiang Xin, Nov 10, 2020
  166. Junio C HamanoNov 10, 2020
  167. Jiang XinNov 11, 2020
  168. 2/2 receive-pack: gently write messages to proc-receiveJiang Xin, Nov 10, 2020
  169. Jeff KingNov 10, 2020
  170. Jiang XinNov 11, 2020
  171. Junio C HamanoNov 10, 2020
  172. Junio C HamanoNov 10, 2020
  173. 1/3 t5411: new helper filter_out_user_friendly_and_stable_outputJiang Xin, Nov 11, 2020
  174. 0/3 jx/t5411-flake-fixJiang Xin, Nov 11, 2020
  175. 2/3 receive-pack: gently write messages to proc-receiveJiang Xin, Nov 11, 2020
  176. 3/3 receive-pack: use default version 0 for proc-receiveJiang Xin, Nov 11, 2020
  177. Jiang XinNov 10, 2020
  178. Junio C HamanoNov 5, 2020
  179. SZEDER GáborJan 17, 2021
  180. Jiang XinJan 18, 2021
  181. SZEDER GáborJan 20, 2021
  182. Jiang XinJan 21, 2021
  183. SZEDER GáborJan 21, 2021
  184. 2/2 t5411: refactor check of refs using test_cmp_refsJiang Xin, Jan 18, 2021
  185. 1/2 t5411: remove file after use to prevent overwritingJiang Xin, Jan 18, 2021
  186. Johannes SixtJan 18, 2021
  187. Jiang XinJan 19, 2021
  188. 1/2 t5411: use different out file to prevent overwritingJiang Xin, Jan 19, 2021
  189. SZEDER GáborJan 20, 2021
  190. 2/2 t5411: refactor check of refs using test_cmp_refsJiang Xin, Jan 21, 2021
  191. 1/2 t5411: use different out file to prevent overwritingJiang Xin, Jan 21, 2021
  192. 0/2 use unique out file in t5411Jiang Xin, Jan 21, 2021
  193. Junio C HamanoFeb 11, 2021
  194. Jiang XinFeb 13, 2021
  195. Jiang XinJan 21, 2021
  196. 2/2 t5411: refactor check of refs using test_cmp_refsJiang Xin, Jan 19, 2021
  197. 0/2 t5411 out file overwrite fixJiang Xin, Jan 19, 2021
  198. 05/10 New capability "report-status-v2" for git-pushJiang Xin, Aug 27, 2020
  199. 08/10 t5411: test updates of remote-tracking branchesJiang Xin, Aug 27, 2020
  200. 09/10 transport: parse report options for tracking refsJiang Xin, Aug 27, 2020
  201. 06/10 doc: add document for capability report-status-v2Jiang Xin, Aug 27, 2020
  202. 10/10 doc: add documentation for the proc-receive hookJiang Xin, Aug 27, 2020
  203. 01/10 transport: not report a non-head push as a branchJiang Xin, Aug 24, 2020
  204. 02/10 t5411: add basic test cases for proc-receive hookJiang Xin, Aug 24, 2020
  205. 03/10 receive-pack: add new proc-receive hookJiang Xin, Aug 24, 2020
  206. 04/10 receive-pack: feed report options to post-receiveJiang Xin, Aug 24, 2020
  207. 06/10 doc: add document for capability report-status-v2Jiang Xin, Aug 24, 2020
  208. 07/10 receive-pack: new config receive.procReceiveRefsJiang Xin, Aug 24, 2020
  209. 08/10 t5411: test updates of remote-tracking branchesJiang Xin, Aug 24, 2020
  210. 09/10 transport: parse report options for tracking refsJiang Xin, Aug 24, 2020
  211. 05/10 New capability "report-status-v2" for git-pushJiang Xin, Aug 24, 2020
  212. 10/10 doc: add documentation for the proc-receive hookJiang Xin, Aug 24, 2020
  213. 02/11 t5411: add basic test cases for proc-receive hookJiang Xin, May 18, 2020
  214. 04/11 New capability "report-status-v2" for git-pushJiang Xin, May 18, 2020
  215. 03/11 receive-pack: add new proc-receive hookJiang Xin, May 18, 2020
  216. 06/11 receive-pack: feed report options to post-receiveJiang Xin, May 18, 2020
  217. 07/11 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, May 18, 2020
  218. 09/11 t5411: test updates of remote-tracking branchesJiang Xin, May 18, 2020
  219. 08/11 receive-pack: new config receive.procReceiveRefsJiang Xin, May 18, 2020
  220. 10/11 transport: parse report options for tracking refsJiang Xin, May 18, 2020
  221. 11/11 doc: add documentation for the proc-receive hookJiang Xin, May 18, 2020
  222. 05/11 doc: add document for capability report-status-v2Jiang Xin, May 18, 2020
  223. 4/7 receive-pack: feed report options to post-receiveJiang Xin, May 7, 2020
  224. 3/7 New capability "report-status-v2" for git-pushJiang Xin, May 7, 2020
  225. 5/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, May 7, 2020
  226. 2/7 receive-pack: add new proc-receive hookJiang Xin, May 7, 2020
  227. 6/7 receive-pack: new config receive.procReceiveRefsJiang Xin, May 7, 2020
  228. 7/7 doc: add documentation for the proc-receive hookJiang Xin, May 7, 2020
  229. 3/7 New capability "report-status-v2" for git-pushJiang Xin, May 5, 2020
  230. 8/7 fixup! New capability "report-status-v2" for git-pushJiang Xin, May 5, 2020
  231. 4/7 receive-pack: feed report options to post-receiveJiang Xin, May 5, 2020
  232. 7/7 doc: add documentation for the proc-receive hookJiang Xin, May 5, 2020
  233. 6/7 receive-pack: new config receive.procReceiveRefsJiang Xin, May 5, 2020
  234. 2/7 receive-pack: add new proc-receive hookJiang Xin, May 5, 2020
  235. 5/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, May 5, 2020
  236. Jeff KingMay 7, 2020
  237. 4/7 send-pack: extension for client-side status reportJiang Xin, Apr 14, 2020
  238. Junio C HamanoApr 15, 2020
  239. 5/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 14, 2020
  240. 7/7 doc: add documentation for the proc-receive hookJiang Xin, Apr 14, 2020
  241. 6/7 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 14, 2020
  242. 6/8 receive-pack: extension for server-side reportJiang Xin, Apr 12, 2020
  243. 8/8 doc: add documentation for the proc-receive hookJiang Xin, Apr 12, 2020
  244. 7/8 send-pack: extension for client-side status reportJiang Xin, Apr 12, 2020
  245. 4/8 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 12, 2020
  246. Junio C HamanoApr 12, 2020
  247. Jiang XinApr 13, 2020
  248. 5/8 connect: export parse_feature_value()Jiang Xin, Apr 12, 2020
  249. 1/6 transport: not report a non-head push as a branchJiang Xin, Apr 7, 2020
  250. 3/6 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 7, 2020
  251. 2/6 receive-pack: add new proc-receive hookJiang Xin, Apr 7, 2020
  252. 4/6 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 7, 2020
  253. 6/6 doc: add documentation for the proc-receive hookJiang Xin, Apr 7, 2020
  254. 5/6 receive-pack: refactor report for proc-receiveJiang Xin, Apr 7, 2020
  255. 1/7 transport: not report a non-head push as a branchJiang Xin, Apr 4, 2020
  256. 3/7 refs.c: refactor to reuse ref_is_hidden()Jiang Xin, Apr 4, 2020
  257. 4/7 receive-pack: new config receive.procReceiveRefsJiang Xin, Apr 4, 2020
  258. 7/7 doc: add documentation for the proc-receive hookJiang Xin, Apr 4, 2020
  259. 2/7 receive-pack: add new proc-receive hookJiang Xin, Apr 4, 2020
  260. 5/7 receive-pack: refactor report for proc-receiveJiang Xin, Apr 4, 2020
  261. 6/7 t5412: test the proc-receive hook on HTTP protocolJiang Xin, Apr 4, 2020
  262. 7/7 doc: add documentation for the proc-receive hookJiang Xin, Apr 3, 2020
  263. 6/7 t5412: test proc-receive hook on HTTP protocolJiang Xin, Apr 3, 2020
  264. 5/7 receive-pack: refactor report for proc-receiveJiang Xin, Apr 2, 2020
  265. 7/7 doc: add documentation for the proc-receive hookJiang Xin, Apr 2, 2020
  266. 6/7 t5412: test proc-receive hook on HTTP protocolJiang Xin, Apr 2, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.