@matheusbsbs / matheus-bagliano / commits / 31e8595a11
Fork 0

receive-pack: new config receive.procReceiveRefs

Add a new multi-valued config variable "receive.procReceiveRefs" for `receive-pack` command, like the follows: git config --system --add receive.procReceiveRefs refs/for git config --system --add receive.procReceiveRefs refs/drafts If the specific prefix strings given by the config variables match the reference names of the commands which are sent from git client to `receive-pack`, these commands will be executed by an external hook (named "proc-receive"), instead of the internal `execute_commands` function. For example, if it is set to "refs/for", pushing to a reference such as "refs/for/master" will not create or update reference "refs/for/master", but may create or update a pull request directly by running the hook "proc-receive". Optional modifiers can be provided in the beginning of the value to filter commands for specific actions: create (a), modify (m), delete (d). A `!` can be included in the modifiers to negate the reference prefix entry. E.g.: git config --system --add receive.procReceiveRefs ad:refs/heads git config --system --add receive.procReceiveRefs !:refs/heads Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jiang Xin committed Aug 27, 2020 at 11:45 UTC 31e8595a1132187f99792a4b889c2128cd9253ef
7 files changed +494 -7
Documentation/config/receive.txt
+22
@@ -114,6 +114,28 @@ receive.hideRefs::
114 An attempt to update or delete a hidden ref by `git push` is
115 rejected.
116
117 +receive.procReceiveRefs::
118 + This is a multi-valued variable that defines reference prefixes
119 + to match the commands in `receive-pack`. Commands matching the
120 + prefixes will be executed by an external hook "proc-receive",
121 + instead of the internal `execute_commands` function. If this
122 + variable is not defined, the "proc-receive" hook will never be
123 + used, and all commands will be executed by the internal
124 + `execute_commands` function.
125 ++
126 +For example, if this variable is set to "refs/for", pushing to reference
127 +such as "refs/for/master" will not create or update a reference named
128 +"refs/for/master", but may create or update a pull request directly by
129 +running the hook "proc-receive".
130 ++
131 +Optional modifiers can be provided in the beginning of the value to filter
132 +commands for specific actions: create (a), modify (m), delete (d).
133 +A `!` can be included in the modifiers to negate the reference prefix entry.
134 +E.g.:
135 ++
136 + git config --system --add receive.procReceiveRefs ad:refs/heads
137 + git config --system --add receive.procReceiveRefs !:refs/heads
138 +
139 receive.updateServerInfo::
140 If set to true, git-receive-pack will run git-update-server-info
141 after receiving data from git-push and updating refs.
builtin/receive-pack.c
+99 -7
@@ -97,6 +97,17 @@ static int keepalive_in_sec = 5;
97
98 static struct tmp_objdir *tmp_objdir;
99
100 +static struct proc_receive_ref {
101 + unsigned int want_add:1,
102 + want_delete:1,
103 + want_modify:1,
104 + negative_ref:1;
105 + char *ref_prefix;
106 + struct proc_receive_ref *next;
107 +} *proc_receive_ref;
108 +
109 +static void proc_receive_ref_append(const char *prefix);
110 +
111 static enum deny_action parse_deny_action(const char *var, const char *value)
112 {
113 if (value) {
@@ -229,6 +240,13 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
240 return 0;
241 }
242
243 + if (strcmp(var, "receive.procreceiverefs") == 0) {
244 + if (!value)
245 + return config_error_nonbool(var);
246 + proc_receive_ref_append(value);
247 + return 0;
248 + }
249 +
250 return git_default_config(var, value, cb);
251 }
252
@@ -324,6 +342,79 @@ struct command {
342 char ref_name[FLEX_ARRAY]; /* more */
343 };
344
345 +static void proc_receive_ref_append(const char *prefix)
346 +{
347 + struct proc_receive_ref *ref_pattern;
348 + char *p;
349 + int len;
350 +
351 + ref_pattern = xcalloc(1, sizeof(struct proc_receive_ref));
352 + p = strchr(prefix, ':');
353 + if (p) {
354 + while (prefix < p) {
355 + if (*prefix == 'a')
356 + ref_pattern->want_add = 1;
357 + else if (*prefix == 'd')
358 + ref_pattern->want_delete = 1;
359 + else if (*prefix == 'm')
360 + ref_pattern->want_modify = 1;
361 + else if (*prefix == '!')
362 + ref_pattern->negative_ref = 1;
363 + prefix++;
364 + }
365 + prefix++;
366 + } else {
367 + ref_pattern->want_add = 1;
368 + ref_pattern->want_delete = 1;
369 + ref_pattern->want_modify = 1;
370 + }
371 + len = strlen(prefix);
372 + while (len && prefix[len - 1] == '/')
373 + len--;
374 + ref_pattern->ref_prefix = xmemdupz(prefix, len);
375 + if (!proc_receive_ref) {
376 + proc_receive_ref = ref_pattern;
377 + } else {
378 + struct proc_receive_ref *end;
379 +
380 + end = proc_receive_ref;
381 + while (end->next)
382 + end = end->next;
383 + end->next = ref_pattern;
384 + }
385 +}
386 +
387 +static int proc_receive_ref_matches(struct command *cmd)
388 +{
389 + struct proc_receive_ref *p;
390 +
391 + if (!proc_receive_ref)
392 + return 0;
393 +
394 + for (p = proc_receive_ref; p; p = p->next) {
395 + const char *match = p->ref_prefix;
396 + const char *remains;
397 +
398 + if (!p->want_add && is_null_oid(&cmd->old_oid))
399 + continue;
400 + else if (!p->want_delete && is_null_oid(&cmd->new_oid))
401 + continue;
402 + else if (!p->want_modify &&
403 + !is_null_oid(&cmd->old_oid) &&
404 + !is_null_oid(&cmd->new_oid))
405 + continue;
406 +
407 + if (skip_prefix(cmd->ref_name, match, &remains) &&
408 + (!*remains || *remains == '/')) {
409 + if (!p->negative_ref)
410 + return 1;
411 + } else if (p->negative_ref) {
412 + return 1;
413 + }
414 + }
415 + return 0;
416 +}
417 +
418 static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
419 static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
420
@@ -1812,14 +1903,15 @@ static void execute_commands(struct command *commands,
1903 * Try to find commands that have special prefix in their reference names,
1904 * and mark them to run an external "proc-receive" hook later.
1905 */
1815 - for (cmd = commands; cmd; cmd = cmd->next) {
1816 - if (!should_process_cmd(cmd))
1817 - continue;
1906 + if (proc_receive_ref) {
1907 + for (cmd = commands; cmd; cmd = cmd->next) {
1908 + if (!should_process_cmd(cmd))
1909 + continue;
1910
1819 - /* TODO: replace the fixed prefix by looking up git config variables. */
1820 - if (!strncmp(cmd->ref_name, "refs/for/", 9)) {
1821 - cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED;
1822 - run_proc_receive = 1;
1911 + if (proc_receive_ref_matches(cmd)) {
1912 + cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED;
1913 + run_proc_receive = 1;
1914 + }
1915 }
1916 }
1917
t/t5411/once-0010-report-status-v1.sh
+4
@@ -1,3 +1,7 @@
1 +test_expect_success "setup receive.procReceiveRefs" '
2 + git -C "$upstream" config --add receive.procReceiveRefs refs/for
3 +'
4 +
5 test_expect_success "setup proc-receive hook" '
6 write_script "$upstream/hooks/proc-receive" <<-EOF
7 printf >&2 "# proc-receive hook\n"
t/t5411/test-0010-proc-receive-settings.sh new
+7
@@ -0,0 +1,7 @@
1 +test_expect_success "add two receive.procReceiveRefs settings" '
2 + (
3 + cd "$upstream" &&
4 + git config --add receive.procReceiveRefs refs/for &&
5 + git config --add receive.procReceiveRefs refs/review/
6 + )
7 +'
t/t5411/test-0040-process-all-refs.sh new
+113
@@ -0,0 +1,113 @@
1 +test_expect_success "config receive.procReceiveRefs = refs ($PROTOCOL)" '
2 + git -C "$upstream" config --unset-all receive.procReceiveRefs &&
3 + git -C "$upstream" config --add receive.procReceiveRefs refs
4 +'
5 +
6 +# Refs of upstream : master(A)
7 +# Refs of workbench: master(A) tags/v123
8 +test_expect_success "setup upstream branches ($PROTOCOL)" '
9 + (
10 + cd "$upstream" &&
11 + git update-ref refs/heads/master $B &&
12 + git update-ref refs/heads/foo $A &&
13 + git update-ref refs/heads/bar $A &&
14 + git update-ref refs/heads/baz $A
15 + )
16 +
17 +'
18 +
19 +test_expect_success "setup proc-receive hook ($PROTOCOL)" '
20 + write_script "$upstream/hooks/proc-receive" <<-EOF
21 + printf >&2 "# proc-receive hook\n"
22 + test-tool proc-receive -v \
23 + -r "ok refs/heads/master" \
24 + -r "option fall-through" \
25 + -r "ok refs/heads/foo" \
26 + -r "option fall-through" \
27 + -r "ok refs/heads/bar" \
28 + -r "option fall-through" \
29 + -r "ok refs/for/master/topic" \
30 + -r "option refname refs/pull/123/head" \
31 + -r "option old-oid $A" \
32 + -r "option new-oid $B" \
33 + -r "ok refs/for/next/topic" \
34 + -r "option refname refs/pull/124/head" \
35 + -r "option old-oid $B" \
36 + -r "option new-oid $A" \
37 + -r "option forced-update"
38 + EOF
39 +'
40 +
41 +# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
42 +# Refs of workbench: master(A) tags/v123
43 +# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A)
44 +test_expect_success "proc-receive: process all refs ($PROTOCOL)" '
45 + git -C workbench push -f origin \
46 + HEAD:refs/heads/master \
47 + :refs/heads/foo \
48 + $B:refs/heads/bar \
49 + HEAD:refs/for/master/topic \
50 + HEAD:refs/for/next/topic \
51 + >out 2>&1 &&
52 + make_user_friendly_and_stable_output <out >actual &&
53 + cat >expect <<-EOF &&
54 + remote: # pre-receive hook
55 + remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
56 + remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
57 + remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
58 + remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
59 + remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
60 + remote: # proc-receive hook
61 + remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
62 + remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
63 + remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
64 + remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
65 + remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
66 + remote: proc-receive> ok refs/heads/master
67 + remote: proc-receive> option fall-through
68 + remote: proc-receive> ok refs/heads/foo
69 + remote: proc-receive> option fall-through
70 + remote: proc-receive> ok refs/heads/bar
71 + remote: proc-receive> option fall-through
72 + remote: proc-receive> ok refs/for/master/topic
73 + remote: proc-receive> option refname refs/pull/123/head
74 + remote: proc-receive> option old-oid <COMMIT-A>
75 + remote: proc-receive> option new-oid <COMMIT-B>
76 + remote: proc-receive> ok refs/for/next/topic
77 + remote: proc-receive> option refname refs/pull/124/head
78 + remote: proc-receive> option old-oid <COMMIT-B>
79 + remote: proc-receive> option new-oid <COMMIT-A>
80 + remote: proc-receive> option forced-update
81 + remote: # post-receive hook
82 + remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
83 + remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
84 + remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
85 + remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
86 + remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
87 + To <URL/of/upstream.git>
88 + <OID-A>..<OID-B> <COMMIT-B> -> bar
89 + - [deleted] foo
90 + + <OID-B>...<OID-A> HEAD -> master (forced update)
91 + <OID-A>..<OID-B> HEAD -> refs/pull/123/head
92 + + <OID-B>...<OID-A> HEAD -> refs/pull/124/head (forced update)
93 + EOF
94 + test_cmp expect actual &&
95 + git -C "$upstream" show-ref >out &&
96 + make_user_friendly_and_stable_output <out >actual &&
97 + cat >expect <<-EOF &&
98 + <COMMIT-B> refs/heads/bar
99 + <COMMIT-A> refs/heads/baz
100 + <COMMIT-A> refs/heads/master
101 + EOF
102 + test_cmp expect actual
103 +'
104 +
105 +# Refs of upstream : master(A) bar(A) baz(B)
106 +# Refs of workbench: master(A) tags/v123
107 +test_expect_success "cleanup ($PROTOCOL)" '
108 + (
109 + cd "$upstream" &&
110 + git update-ref -d refs/heads/bar &&
111 + git update-ref -d refs/heads/baz
112 + )
113 +'
t/t5411/test-0041-process-all-refs--porcelain.sh new
+114
@@ -0,0 +1,114 @@
1 +test_expect_success "config receive.procReceiveRefs = refs ($PROTOCOL/porcelain)" '
2 + git -C "$upstream" config --unset-all receive.procReceiveRefs &&
3 + git -C "$upstream" config --add receive.procReceiveRefs refs
4 +'
5 +
6 +# Refs of upstream : master(A)
7 +# Refs of workbench: master(A) tags/v123
8 +test_expect_success "setup upstream branches ($PROTOCOL/porcelain)" '
9 + (
10 + cd "$upstream" &&
11 + git update-ref refs/heads/master $B &&
12 + git update-ref refs/heads/foo $A &&
13 + git update-ref refs/heads/bar $A &&
14 + git update-ref refs/heads/baz $A
15 + )
16 +
17 +'
18 +
19 +test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" '
20 + write_script "$upstream/hooks/proc-receive" <<-EOF
21 + printf >&2 "# proc-receive hook\n"
22 + test-tool proc-receive -v \
23 + -r "ok refs/heads/master" \
24 + -r "option fall-through" \
25 + -r "ok refs/heads/foo" \
26 + -r "option fall-through" \
27 + -r "ok refs/heads/bar" \
28 + -r "option fall-through" \
29 + -r "ok refs/for/master/topic" \
30 + -r "option refname refs/pull/123/head" \
31 + -r "option old-oid $A" \
32 + -r "option new-oid $B" \
33 + -r "ok refs/for/next/topic" \
34 + -r "option refname refs/pull/124/head" \
35 + -r "option old-oid $B" \
36 + -r "option new-oid $A" \
37 + -r "option forced-update"
38 + EOF
39 +'
40 +
41 +# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
42 +# Refs of workbench: master(A) tags/v123
43 +# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A)
44 +test_expect_success "proc-receive: process all refs ($PROTOCOL/porcelain)" '
45 + git -C workbench push --porcelain -f origin \
46 + HEAD:refs/heads/master \
47 + :refs/heads/foo \
48 + $B:refs/heads/bar \
49 + HEAD:refs/for/master/topic \
50 + HEAD:refs/for/next/topic \
51 + >out 2>&1 &&
52 + make_user_friendly_and_stable_output <out >actual &&
53 + cat >expect <<-EOF &&
54 + remote: # pre-receive hook
55 + remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
56 + remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
57 + remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
58 + remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
59 + remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
60 + remote: # proc-receive hook
61 + remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
62 + remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
63 + remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
64 + remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
65 + remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
66 + remote: proc-receive> ok refs/heads/master
67 + remote: proc-receive> option fall-through
68 + remote: proc-receive> ok refs/heads/foo
69 + remote: proc-receive> option fall-through
70 + remote: proc-receive> ok refs/heads/bar
71 + remote: proc-receive> option fall-through
72 + remote: proc-receive> ok refs/for/master/topic
73 + remote: proc-receive> option refname refs/pull/123/head
74 + remote: proc-receive> option old-oid <COMMIT-A>
75 + remote: proc-receive> option new-oid <COMMIT-B>
76 + remote: proc-receive> ok refs/for/next/topic
77 + remote: proc-receive> option refname refs/pull/124/head
78 + remote: proc-receive> option old-oid <COMMIT-B>
79 + remote: proc-receive> option new-oid <COMMIT-A>
80 + remote: proc-receive> option forced-update
81 + remote: # post-receive hook
82 + remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
83 + remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
84 + remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
85 + remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
86 + remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
87 + To <URL/of/upstream.git>
88 + <COMMIT-B>:refs/heads/bar <OID-A>..<OID-B>
89 + - :refs/heads/foo [deleted]
90 + + HEAD:refs/heads/master <OID-B>...<OID-A> (forced update)
91 + HEAD:refs/pull/123/head <OID-A>..<OID-B>
92 + + HEAD:refs/pull/124/head <OID-B>...<OID-A> (forced update)
93 + Done
94 + EOF
95 + test_cmp expect actual &&
96 + git -C "$upstream" show-ref >out &&
97 + make_user_friendly_and_stable_output <out >actual &&
98 + cat >expect <<-EOF &&
99 + <COMMIT-B> refs/heads/bar
100 + <COMMIT-A> refs/heads/baz
101 + <COMMIT-A> refs/heads/master
102 + EOF
103 + test_cmp expect actual
104 +'
105 +
106 +# Refs of upstream : master(A) bar(A) baz(B)
107 +# Refs of workbench: master(A) tags/v123
108 +test_expect_success "cleanup ($PROTOCOL/porcelain)" '
109 + (
110 + cd "$upstream" &&
111 + git update-ref -d refs/heads/bar &&
112 + git update-ref -d refs/heads/baz
113 + )
114 +'
t/t5411/test-0050-proc-receive-refs-with-modifiers.sh new
+135
@@ -0,0 +1,135 @@
1 +test_expect_success "config receive.procReceiveRefs with modifiers ($PROTOCOL)" '
2 + (
3 + cd "$upstream" &&
4 + git config --unset-all receive.procReceiveRefs &&
5 + git config --add receive.procReceiveRefs m:refs/heads/master &&
6 + git config --add receive.procReceiveRefs ad:refs/heads &&
7 + git config --add receive.procReceiveRefs "a!:refs/heads"
8 + )
9 +'
10 +
11 +test_expect_success "setup proc-receive hook ($PROTOCOL)" '
12 + write_script "$upstream/hooks/proc-receive" <<-EOF
13 + printf >&2 "# proc-receive hook\n"
14 + test-tool proc-receive -v \
15 + -r "ok refs/heads/master" \
16 + -r "option refname refs/pull/123/head" \
17 + -r "option old-oid $A" \
18 + -r "option new-oid $B" \
19 + -r "ok refs/tags/v123 " \
20 + -r "option refname refs/pull/124/head"
21 + EOF
22 +'
23 +
24 +# Refs of upstream : master(A)
25 +# Refs of workbench: master(A) tags/v123
26 +# git push : master(B) tags/v123
27 +test_expect_success "proc-receive: update branch and new tag ($PROTOCOL)" '
28 + git -C workbench push origin \
29 + $B:refs/heads/master \
30 + v123 >out 2>&1 &&
31 + make_user_friendly_and_stable_output <out >actual &&
32 + cat >expect <<-EOF &&
33 + remote: # pre-receive hook
34 + remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
35 + remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
36 + remote: # proc-receive hook
37 + remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
38 + remote: proc-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
39 + remote: proc-receive> ok refs/heads/master
40 + remote: proc-receive> option refname refs/pull/123/head
41 + remote: proc-receive> option old-oid <COMMIT-A>
42 + remote: proc-receive> option new-oid <COMMIT-B>
43 + remote: proc-receive> ok refs/tags/v123
44 + remote: proc-receive> option refname refs/pull/124/head
45 + remote: # post-receive hook
46 + remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
47 + remote: post-receive< <ZERO-OID> <TAG-v123> refs/pull/124/head
48 + To <URL/of/upstream.git>
49 + <OID-A>..<OID-B> <COMMIT-B> -> refs/pull/123/head
50 + * [new reference] v123 -> refs/pull/124/head
51 + EOF
52 + test_cmp expect actual &&
53 + git -C "$upstream" show-ref >out &&
54 + make_user_friendly_and_stable_output <out >actual &&
55 + cat >expect <<-EOF &&
56 + <COMMIT-A> refs/heads/master
57 + EOF
58 + test_cmp expect actual
59 +'
60 +
61 +# Refs of upstream : master(A)
62 +# Refs of workbench: master(A) tags/v123
63 +test_expect_success "setup upstream: create tags/v123 ($PROTOCOL)" '
64 + git -C "$upstream" update-ref refs/heads/topic $A &&
65 + git -C "$upstream" update-ref refs/tags/v123 $TAG &&
66 + git -C "$upstream" show-ref >out &&
67 + make_user_friendly_and_stable_output <out >actual &&
68 + cat >expect <<-EOF &&
69 + <COMMIT-A> refs/heads/master
70 + <COMMIT-A> refs/heads/topic
71 + <TAG-v123> refs/tags/v123
72 + EOF
73 + test_cmp expect actual
74 +'
75 +
76 +test_expect_success "setup proc-receive hook ($PROTOCOL)" '
77 + write_script "$upstream/hooks/proc-receive" <<-EOF
78 + printf >&2 "# proc-receive hook\n"
79 + test-tool proc-receive -v \
80 + -r "ok refs/heads/master" \
81 + -r "option refname refs/pull/123/head" \
82 + -r "option old-oid $A" \
83 + -r "option new-oid $ZERO_OID" \
84 + -r "ok refs/heads/next" \
85 + -r "option refname refs/pull/124/head" \
86 + -r "option new-oid $A"
87 + EOF
88 +'
89 +
90 +# Refs of upstream : master(A) topic(A) tags/v123
91 +# Refs of workbench: master(A) tags/v123
92 +# git push : NULL topic(B) NULL next(A)
93 +test_expect_success "proc-receive: create/delete branch, and delete tag ($PROTOCOL)" '
94 + git -C workbench push origin \
95 + :refs/heads/master \
96 + $B:refs/heads/topic \
97 + $A:refs/heads/next \
98 + :refs/tags/v123 >out 2>&1 &&
99 + make_user_friendly_and_stable_output <out >actual &&
100 + cat >expect <<-EOF &&
101 + remote: # pre-receive hook
102 + remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/master
103 + remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic
104 + remote: pre-receive< <TAG-v123> <ZERO-OID> refs/tags/v123
105 + remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
106 + remote: # proc-receive hook
107 + remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/master
108 + remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
109 + remote: proc-receive> ok refs/heads/master
110 + remote: proc-receive> option refname refs/pull/123/head
111 + remote: proc-receive> option old-oid <COMMIT-A>
112 + remote: proc-receive> option new-oid <ZERO-OID>
113 + remote: proc-receive> ok refs/heads/next
114 + remote: proc-receive> option refname refs/pull/124/head
115 + remote: proc-receive> option new-oid <COMMIT-A>
116 + remote: # post-receive hook
117 + remote: post-receive< <COMMIT-A> <ZERO-OID> refs/pull/123/head
118 + remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic
119 + remote: post-receive< <TAG-v123> <ZERO-OID> refs/tags/v123
120 + remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/124/head
121 + To <URL/of/upstream.git>
122 + - [deleted] refs/pull/123/head
123 + <OID-A>..<OID-B> <COMMIT-B> -> topic
124 + - [deleted] v123
125 + * [new reference] <COMMIT-A> -> refs/pull/124/head
126 + EOF
127 + test_cmp expect actual &&
128 + git -C "$upstream" show-ref >out &&
129 + make_user_friendly_and_stable_output <out >actual &&
130 + cat >expect <<-EOF &&
131 + <COMMIT-A> refs/heads/master
132 + <COMMIT-B> refs/heads/topic
133 + EOF
134 + test_cmp expect actual
135 +'