@@ -328,6 +328,7 @@ static void write_head_info(void)
struct command {
struct command *next;
const char *error_string;
+ const char *extra_string;
unsigned int skip_update:1,
did_not_exist:1,
run_proc_receive:2;
@@ -913,7 +914,12 @@ static int read_proc_receive_result(struct packet_reader *reader,
else
hint->error_string = "failed";
code = 1;
- } else if (strcmp("ok", status)) {
+ } else if (!strcmp("ok", status)) {
+ hint->extra_string = xstrdup_or_null(msg);
+ } else if (!strcmp("ft", status)) {
+ /* Reset "run_proc_receive" field, and continue to run in "receive-pack" */
+ hint->run_proc_receive = 0;
+ } else {
strbuf_addf(errmsg, "proc-receive has bad status '%s' for '%s'\n",
status, reader->line);
return -1;
@@ -2183,12 +2189,17 @@ 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",
- cmd->ref_name);
- else
+ if (!cmd->error_string) {
+ if (!cmd->extra_string)
+ packet_buf_write(&buf, "ok %s\n",
+ cmd->ref_name);
+ else
+ packet_buf_write(&buf, "ok %s%c%s\n",
+ cmd->ref_name, ' ', cmd->extra_string);
+ } else {
packet_buf_write(&buf, "ng %s %s\n",
cmd->ref_name, cmd->error_string);
+ }
}
packet_buf_flush(&buf);
@@ -743,8 +743,8 @@ test_expect_success "setup proc-receive hook" '
test-tool proc-receive -v \
-r "$ZERO_OID $A refs/review/a/b/c/topic ok" \
- -r "$ZERO_OID $A refs/for/next/topic ok" \
- -r "$ZERO_OID $A refs/for/master/topic ok"
+ -r "$ZERO_OID $A refs/for/next/topic ok ref:refs/pull/123/head" \
+ -r "$ZERO_OID $A refs/for/master/topic ok ref:refs/pull/124/head"
EOF
chmod a+x "$upstream/hooks/proc-receive"
'
@@ -769,16 +769,16 @@ test_expect_success "report update of all special refs" '
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/review/a/b/c/topic
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/review/a/b/c/topic ok
- remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/next/topic ok
- remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/master/topic ok
+ remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/next/topic ok ref:refs/pull/123/head
+ remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/master/topic ok ref:refs/pull/124/head
remote: # post-receive hook
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/a/b/c/topic
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
To <URL/of/upstream.git>
- * [new reference] HEAD -> refs/for/next/topic
+ * [new reference] HEAD -> refs/pull/123/head
* [new reference] HEAD -> refs/review/a/b/c/topic
- * [new reference] HEAD -> refs/for/master/topic
+ * [new reference] HEAD -> refs/pull/124/head
EOF
test_cmp expect actual &&
git -C "$upstream" show-ref >out &&
@@ -807,6 +807,7 @@ test_expect_success "setup proc-receive hook" '
# git push : bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A)
test_expect_success "report mixed refs update" '
git -C workbench push origin \
+ $B:refs/heads/master \
HEAD:refs/heads/bar \
HEAD:refs/heads/baz \
HEAD:refs/for/next/topic \
@@ -816,6 +817,7 @@ test_expect_success "report mixed refs update" '
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
@@ -827,12 +829,14 @@ test_expect_success "report mixed refs update" '
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/next/topic ok
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/master/topic ok
remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
To <URL/of/upstream.git>
+ <OID>..<OID> <COMMIT-B> -> master
* [new branch] HEAD -> bar
* [new branch] HEAD -> baz
* [new reference] HEAD -> refs/for/next/topic
@@ -846,6 +850,80 @@ test_expect_success "report mixed refs update" '
<COMMIT-A> refs/heads/bar
<COMMIT-A> refs/heads/baz
<COMMIT-A> refs/heads/foo
+ <COMMIT-B> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "config receive.procReceiveRefs for all ref/" '
+ git -C "$upstream" config --add receive.procReceiveRefs refs/
+'
+
+test_expect_success "setup proc-receive hook" '
+ cat >"$upstream/hooks/proc-receive" <<-EOF &&
+ #!/bin/sh
+
+ printf >&2 "# proc-receive hook\n"
+
+ test-tool proc-receive -v \
+ -r "$B $A refs/heads/master ft" \
+ -r "$A $ZERO_OID refs/heads/foo ft" \
+ -r "$A $B refs/heads/bar ft" \
+ -r "$A $B refs/for/master/topic ok ref:refs/pull/123/head" \
+ -r "$B $A refs/for/next/topic ok ref:refs/pull/124/head"
+ EOF
+ chmod a+x "$upstream/hooks/proc-receive"
+'
+
+# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
+# Refs of workbench: master(A) tags/v123
+# git push -f : (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A)
+test_expect_success "report test: fallthrough" '
+ git -C workbench push -f origin \
+ HEAD:refs/heads/master \
+ :refs/heads/foo \
+ $B:refs/heads/bar \
+ HEAD:refs/for/master/topic \
+ HEAD:refs/for/next/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ 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> <COMMIT-B> <COMMIT-A> refs/heads/master ft
+ remote: proc-receive> <COMMIT-A> <ZERO-OID> refs/heads/foo ft
+ remote: proc-receive> <COMMIT-A> <COMMIT-B> refs/heads/bar ft
+ remote: proc-receive> <COMMIT-A> <COMMIT-B> refs/for/master/topic ok ref:refs/pull/123/head
+ remote: proc-receive> <COMMIT-B> <COMMIT-A> refs/for/next/topic ok ref:refs/pull/124/head
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/next/topic
+ To <URL/of/upstream.git>
+ <OID>..<OID> <COMMIT-B> -> bar
+ - [deleted] foo
+ + <OID>...<OID> HEAD -> master (forced update)
+ * [new reference] HEAD -> refs/pull/123/head
+ * [new reference] HEAD -> refs/pull/124/head
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/bar
+ <COMMIT-A> refs/heads/baz
<COMMIT-A> refs/heads/master
EOF
test_cmp expect actual
@@ -747,37 +747,39 @@ static int push_update_ref_status(struct strbuf *buf,
msg = xstrdup(msg);
strbuf_release(&msg_buf);
- if (!strcmp(msg, "no match")) {
- status = REF_STATUS_NONE;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "up to date")) {
- status = REF_STATUS_UPTODATE;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "non-fast forward")) {
- status = REF_STATUS_REJECT_NONFASTFORWARD;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "already exists")) {
- status = REF_STATUS_REJECT_ALREADY_EXISTS;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "fetch first")) {
- status = REF_STATUS_REJECT_FETCH_FIRST;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "needs force")) {
- status = REF_STATUS_REJECT_NEEDS_FORCE;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "stale info")) {
- status = REF_STATUS_REJECT_STALE;
- FREE_AND_NULL(msg);
- }
- else if (!strcmp(msg, "forced update")) {
- forced = 1;
- FREE_AND_NULL(msg);
+ if (status != REF_STATUS_OK) {
+ if (!strcmp(msg, "no match")) {
+ status = REF_STATUS_NONE;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "up to date")) {
+ status = REF_STATUS_UPTODATE;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "non-fast forward")) {
+ status = REF_STATUS_REJECT_NONFASTFORWARD;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "already exists")) {
+ status = REF_STATUS_REJECT_ALREADY_EXISTS;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "fetch first")) {
+ status = REF_STATUS_REJECT_FETCH_FIRST;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "needs force")) {
+ status = REF_STATUS_REJECT_NEEDS_FORCE;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "stale info")) {
+ status = REF_STATUS_REJECT_STALE;
+ FREE_AND_NULL(msg);
+ }
+ else if (!strcmp(msg, "forced update")) {
+ forced = 1;
+ FREE_AND_NULL(msg);
+ }
}
}
@@ -459,15 +459,18 @@ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int v
}
}
-static void print_ref_status(char flag, const char *summary,
+static void print_ref_status(char flag, const char *summary, char *target_refname,
struct ref *to, struct ref *from, const char *msg,
int porcelain, int summary_width)
{
+ if (!target_refname)
+ target_refname = to->name;
+
if (porcelain) {
if (from)
- fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+ fprintf(stdout, "%c\t%s:%s\t", flag, from->name, target_refname);
else
- fprintf(stdout, "%c\t:%s\t", flag, to->name);
+ fprintf(stdout, "%c\t:%s\t", flag, target_refname);
if (msg)
fprintf(stdout, "%s (%s)\n", summary, msg);
else
@@ -481,9 +484,9 @@ static void print_ref_status(char flag, const char *summary,
fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
summary, reset);
if (from)
- fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
+ fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(target_refname));
else
- fputs(prettify_refname(to->name), stderr);
+ fputs(prettify_refname(target_refname), stderr);
if (msg) {
fputs(" (", stderr);
fputs(msg, stderr);
@@ -495,18 +498,26 @@ static void print_ref_status(char flag, const char *summary,
static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_width)
{
+ char *refname;
+
+ if (ref->remote_status && !strncmp(ref->remote_status, "ref:", 4))
+ refname = ref->remote_status + 4;
+ else
+ refname = ref->name;
+
if (ref->deletion)
- print_ref_status('-', "[deleted]", ref, NULL, NULL,
+ print_ref_status('-', "[deleted]", refname, ref, NULL, NULL,
porcelain, summary_width);
- else if (is_null_oid(&ref->old_oid))
+ else if (is_null_oid(&ref->old_oid)) {
+
print_ref_status('*',
- (starts_with(ref->name, "refs/tags/")
+ (starts_with(refname, "refs/tags/")
? "[new tag]"
- : (starts_with(ref->name, "refs/heads/")
+ : (starts_with(refname, "refs/heads/")
? "[new branch]"
: "[new reference]")),
- ref, ref->peer_ref, NULL, porcelain, summary_width);
- else {
+ refname, ref, ref->peer_ref, NULL, porcelain, summary_width);
+ } else {
struct strbuf quickref = STRBUF_INIT;
char type;
const char *msg;
@@ -525,7 +536,7 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt
strbuf_add_unique_abbrev(&quickref, &ref->new_oid,
DEFAULT_ABBREV);
- print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg,
+ print_ref_status(type, quickref.buf, refname, ref, ref->peer_ref, msg,
porcelain, summary_width);
strbuf_release(&quickref);
}
@@ -542,56 +553,56 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count,
switch(ref->status) {
case REF_STATUS_NONE:
- print_ref_status('X', "[no match]", ref, NULL, NULL,
+ print_ref_status('X', "[no match]", NULL, ref, NULL, NULL,
porcelain, summary_width);
break;
case REF_STATUS_REJECT_NODELETE:
- print_ref_status('!', "[rejected]", ref, NULL,
+ print_ref_status('!', "[rejected]", NULL, ref, NULL,
"remote does not support deleting refs",
porcelain, summary_width);
break;
case REF_STATUS_UPTODATE:
- print_ref_status('=', "[up to date]", ref,
+ print_ref_status('=', "[up to date]", NULL, ref,
ref->peer_ref, NULL, porcelain, summary_width);
break;
case REF_STATUS_REJECT_NONFASTFORWARD:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"non-fast-forward", porcelain, summary_width);
break;
case REF_STATUS_REJECT_ALREADY_EXISTS:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"already exists", porcelain, summary_width);
break;
case REF_STATUS_REJECT_FETCH_FIRST:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"fetch first", porcelain, summary_width);
break;
case REF_STATUS_REJECT_NEEDS_FORCE:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"needs force", porcelain, summary_width);
break;
case REF_STATUS_REJECT_STALE:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"stale info", porcelain, summary_width);
break;
case REF_STATUS_REJECT_SHALLOW:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"new shallow roots not allowed",
porcelain, summary_width);
break;
case REF_STATUS_REMOTE_REJECT:
- print_ref_status('!', "[remote rejected]", ref,
+ print_ref_status('!', "[remote rejected]", NULL, ref,
ref->deletion ? NULL : ref->peer_ref,
ref->remote_status, porcelain, summary_width);
break;
case REF_STATUS_EXPECTING_REPORT:
- print_ref_status('!', "[remote failure]", ref,
+ print_ref_status('!', "[remote failure]", NULL, ref,
ref->deletion ? NULL : ref->peer_ref,
"remote failed to report status",
porcelain, summary_width);
break;
case REF_STATUS_ATOMIC_PUSH_FAILED:
- print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ print_ref_status('!', "[rejected]", NULL, ref, ref->peer_ref,
"atomic push failed", porcelain, summary_width);
break;
case REF_STATUS_OK: