diff mbox series

[v10,1/8] transport: not report a non-head push as a branch

Message ID 20200412133022.17590-2-worldhello.net@gmail.com (mailing list archive)
State New, archived
Headers show
Series New proc-receive hook for centralized workflow | expand

Commit Message

Jiang Xin April 12, 2020, 1:30 p.m. UTC
From: Jiang Xin <zhiyou.jx@alibaba-inc.com>

When pushing a new reference (not a head or tag), report it as a new
reference instead of a new branch.

Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>
---
 t/t5411-proc-receive-hook.sh               | 75 +++++++++++++++++++
 t/t5411/common-functions.sh                | 50 +++++++++++++
 t/t5411/common-test-cases.sh               | 43 +++++++++++
 t/t5412-proc-receive-hook-http-protocol.sh | 86 ++++++++++++++++++++++
 t/t5516-fetch-push.sh                      |  2 +-
 transport.c                                |  9 ++-
 6 files changed, 261 insertions(+), 4 deletions(-)
 create mode 100755 t/t5411-proc-receive-hook.sh
 create mode 100644 t/t5411/common-functions.sh
 create mode 100644 t/t5411/common-test-cases.sh
 create mode 100755 t/t5412-proc-receive-hook-http-protocol.sh

Comments

Junio C Hamano April 12, 2020, 8:26 p.m. UTC | #1
Jiang Xin <worldhello.net@gmail.com> writes:

>  create mode 100755 t/t5411-proc-receive-hook.sh
>  create mode 100644 t/t5411/common-functions.sh
>  create mode 100644 t/t5411/common-test-cases.sh
>  create mode 100755 t/t5412-proc-receive-hook-http-protocol.sh
>
> diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh
> new file mode 100755
> index 0000000000..ef289fe92a
> --- /dev/null
> +++ b/t/t5411-proc-receive-hook.sh
> @@ -0,0 +1,75 @@
> +#!/bin/sh
> +#
> +# Copyright (c) 2020 Jiang Xin
> +#
> +
> +test_description='Test proc-receive hook'
> +
> +. ./test-lib.sh
> +
> +. "$TEST_DIRECTORY"/t5411/common-functions.sh
> +
> +# Format the output of git-push, git-show-ref and other commands to make a
> +# user-friendly and stable text.  In addition to the common format method,
> +# we also replace the URL of different protocol for the upstream repository
> +# with a fixed pattern.
> +make_user_friendly_and_stable_output () {
> +	make_user_friendly_and_stable_output_common | sed \
> +		-e "s#To ../upstream.git#To <URL/of/upstream.git>#"

Break the line immediately after the pipe, and begin the next line
with the command.  That way, the shell knows that you haven't
finished giving the command at the end of the first line, and you do
not have to use a backslash, i.e.

    make_user_friendly |
    sed -e 's/from/to/'

> +		cd workbench &&
> +		# Try to make a stable fixed width for abbreviated commit ID,
> +		# this fixed-width oid will be replaced with "<OID>".
> +		git config core.abbrev 7 &&
> +		git remote add origin ../upstream.git &&
> +		git update-ref refs/heads/master $A &&
> +		git tag -m "v123" v123 $A &&
> +		git push origin \
> +			$B:refs/heads/master \
> +			$A:refs/heads/next
> +	) &&
> +	TAG=$(git -C workbench rev-parse v123) &&
> +
> +	# setup pre-receive hook
> +	cat >upstream.git/hooks/pre-receive <<-\EOF &&

Use write_script and you don't need the chmod at the end.

> +	#!/bin/sh
> +
> +	echo >&2 "# pre-receive hook"
> +
> +	while read old new ref
> +	do
> +		echo >&2 "pre-receive< $old $new $ref"
> +	done
> +	EOF

Perhaps "exec >&2" upfront?

> +	# setup post-receive hook
> +	cat >upstream.git/hooks/post-receive <<-\EOF &&
> +	#!/bin/sh
> +
> +	echo >&2 "# post-receive hook"
> +
> +	while read old new ref
> +	do
> +		echo >&2 "post-receive< $old $new $ref"
> +	done
> +	EOF
> +
> +	chmod a+x \
> +		upstream.git/hooks/pre-receive \
> +		upstream.git/hooks/post-receive &&

Ditto.

> +	upstream=upstream.git
> +'
> +
> +# Include test cases for both file and HTTP protocol
> +. "$TEST_DIRECTORY"/t5411/common-test-cases.sh
> +
> +test_done


> diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh
> new file mode 100644
> index 0000000000..6e400c0625
> --- /dev/null
> +++ b/t/t5411/common-functions.sh
> @@ -0,0 +1,50 @@

It is good that this omits "#!" and leaves the file without +x bit.

> +# Format the output of git-push, git-show-ref and other commands to make a
> +# user-friendly and stable text.  We can easily prepare the expect text
> +# without having to worry about future changes of the commit ID and spaces
> +# of the output.  We also replce single quotes with double quotes, because
> +# it is boring to prepare unquoted single quotes in expect txt.

s/txt/text/

> +make_user_friendly_and_stable_output_common () {
> +	sed \
> +		-e "s/  *\$//" \
> +		-e "s/   */ /g" \
> +		-e "s/'/\"/g" \
> +		-e "s/$A/<COMMIT-A>/g" \
> +		-e "s/$B/<COMMIT-B>/g" \
> +		-e "s/$TAG/<TAG-v123>/g" \
> +		-e "s/$ZERO_OID/<ZERO-OID>/g" \
> +		-e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \
> +		-e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g"
> +}

So a full object name for commit "A" becomes <COMMIT-A> while an
abbreviated one becomes <OID-A>?  OK.  I wonder if we force the full
length (i.e. no abbreviation), the tests become simpler, but it is
OK.  As long as A and B does not share the same 7 hexdigits in any
future hash function we choose, the above will do the right thing
;-)

> diff --git a/t/t5412-proc-receive-hook-http-protocol.sh b/t/t5412-proc-receive-hook-http-protocol.sh
> new file mode 100755
> index 0000000000..e2446d4d32
> --- /dev/null
> +++ b/t/t5412-proc-receive-hook-http-protocol.sh
> @@ -0,0 +1,86 @@
> +#!/bin/sh
> +#
> +# Copyright (c) 2020 Jiang Xin
> +#
> +
> +test_description='Test proc-receive hook for HTTP protocol'
> +
> +. ./test-lib.sh
> +
> +ROOT_PATH="$PWD"
> +. "$TEST_DIRECTORY"/lib-gpg.sh
> +. "$TEST_DIRECTORY"/lib-httpd.sh
> +. "$TEST_DIRECTORY"/lib-terminal.sh
> +start_httpd
> +
> +. "$TEST_DIRECTORY"/t5411/common-functions.sh
> +
> +# Format the output of git-push, git-show-ref and other commands to make a
> +# user-friendly and stable text.  In addition to the common format method,
> +# we also replace the URL of different protocol for the upstream repository
> +# with a fixed pattern.
> +make_user_friendly_and_stable_output () {
> +	make_user_friendly_and_stable_output_common | sed \
> +		-e "s#To http:.*/upstream.git#To <URL/of/upstream.git>#"
> +}

Ditto.

> +# Refs of upstream : master(B)  next(A)
> +# Refs of workbench: master(A)           tags/v123
> +test_expect_success "setup" '
> +	git init --bare upstream.git &&
> +	git -C upstream.git config http.receivepack true &&
> +	git init workbench &&
> +	create_commits_in workbench A B &&
> +	(
> +		cd workbench &&
> +		# Try to make a stable fixed width for abbreviated commit ID,
> +		# this fixed-width oid will be replaced with "<OID>".
> +		git config core.abbrev 7 &&
> +		git remote add origin ../upstream.git &&
> +		git update-ref refs/heads/master $A &&
> +		git tag -m "v123" v123 $A &&
> +		git push origin \
> +			$B:refs/heads/master \
> +			$A:refs/heads/next
> +	) &&
> +	TAG=$(git -C workbench rev-parse v123) &&
> +
> +	# setup pre-receive hook
> +	cat >upstream.git/hooks/pre-receive <<-\EOF &&
> +	#!/bin/sh

Ditto.

> +
> +	echo >&2 "# pre-receive hook"
> +
> +	while read old new ref
> +	do
> +		echo >&2 "pre-receive< $old $new $ref"
> +	done
> +	EOF
> +
> +	# setup post-receive hook
> +	cat >upstream.git/hooks/post-receive <<-\EOF &&
> +	#!/bin/sh
> +
> +	echo >&2 "# post-receive hook"
> +
> +	while read old new ref
> +	do
> +		echo >&2 "post-receive< $old $new $ref"
> +	done
> +	EOF
> +
> +	chmod a+x \
> +		upstream.git/hooks/pre-receive \
> +		upstream.git/hooks/post-receive &&
> +
> +	upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
> +	mv upstream.git "$upstream" &&
> +	git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git
> +'
> +
> +setup_askpass_helper
> +
> +# Include test cases for both file and HTTP protocol
> +. "$TEST_DIRECTORY"/t5411/common-test-cases.sh
> +
> +test_done
> diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
> index 9ff041a093..9e4b9313b5 100755
> --- a/t/t5516-fetch-push.sh
> +++ b/t/t5516-fetch-push.sh
> @@ -1039,7 +1039,7 @@ test_force_fetch_tag "annotated tag" "-f -a -m'tag message'"
>  test_expect_success 'push --porcelain' '
>  	mk_empty testrepo &&
>  	echo >.git/foo  "To testrepo" &&
> -	echo >>.git/foo "*	refs/heads/master:refs/remotes/origin/master	[new branch]"  &&
> +	echo >>.git/foo "*	refs/heads/master:refs/remotes/origin/master	[new reference]"  &&
>  	echo >>.git/foo "Done" &&
>  	git push >.git/bar --porcelain  testrepo refs/heads/master:refs/remotes/origin/master &&
>  	(
> diff --git a/transport.c b/transport.c
> index 1fdc7dac1a..272c0f4046 100644
> --- a/transport.c
> +++ b/transport.c
> @@ -500,9 +500,12 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt
>  				 porcelain, summary_width);
>  	else if (is_null_oid(&ref->old_oid))

This block is about an update to missing "old", i.e. a creation.

>  		print_ref_status('*',
> -			(starts_with(ref->name, "refs/tags/") ? "[new tag]" :
> -			"[new branch]"),
> -			ref, ref->peer_ref, NULL, porcelain, summary_width);

We used to say "if outside refs/tags/, let's call it branch".

> +				 (starts_with(ref->name, "refs/tags/")
> +				  ? "[new tag]"
> +				  : (starts_with(ref->name, "refs/heads/")
> +				     ? "[new branch]"
> +				     : "[new reference]")),
> +				 ref, ref->peer_ref, NULL, porcelain, summary_width);

Now we say "outside refs/heads/ and refs/tags/, that's just a
reference, different from branch".  OK.

Do we ever update refs/remotes/ with this codepath?  Would we want
to label it differently, i.e. as "remote-tracking branch"?

>  	else {
>  		struct strbuf quickref = STRBUF_INIT;
>  		char type;

Thanks.
Jiang Xin April 13, 2020, 11:15 a.m. UTC | #2
Junio C Hamano <gitster@pobox.com> 于2020年4月13日周一 上午4:26写道:
> > +make_user_friendly_and_stable_output () {
> > +     make_user_friendly_and_stable_output_common | sed \
> > +             -e "s#To ../upstream.git#To <URL/of/upstream.git>#"
>
> Break the line immediately after the pipe, and begin the next line
> with the command.  That way, the shell knows that you haven't
> finished giving the command at the end of the first line, and you do
> not have to use a backslash, i.e.
>
>     make_user_friendly |
>     sed -e 's/from/to/'

Will do.

> > +             cd workbench &&
> > +             # Try to make a stable fixed width for abbreviated commit ID,
> > +             # this fixed-width oid will be replaced with "<OID>".
> > +             git config core.abbrev 7 &&
> > +             git remote add origin ../upstream.git &&
> > +             git update-ref refs/heads/master $A &&
> > +             git tag -m "v123" v123 $A &&
> > +             git push origin \
> > +                     $B:refs/heads/master \
> > +                     $A:refs/heads/next
> > +     ) &&
> > +     TAG=$(git -C workbench rev-parse v123) &&
> > +
> > +     # setup pre-receive hook
> > +     cat >upstream.git/hooks/pre-receive <<-\EOF &&
>
> Use write_script and you don't need the chmod at the end.

Yes, it's tedious to write chmod again and again.  Will replace all
the places for writing script.

> > +     #!/bin/sh
> > +
> > +     echo >&2 "# pre-receive hook"
> > +
> > +     while read old new ref
> > +     do
> > +             echo >&2 "pre-receive< $old $new $ref"
> > +     done
> > +     EOF
>
> Perhaps "exec >&2" upfront?

This works for "pre-receive" and "post-receive" script.  But in
"proc-receive" hook, stdout and stderr are different, and standard
output is used for protocol output.

> > diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh
> > new file mode 100644
> > index 0000000000..6e400c0625
> > --- /dev/null
> > +++ b/t/t5411/common-functions.sh
> > @@ -0,0 +1,50 @@
>
> It is good that this omits "#!" and leaves the file without +x bit.
>
> > +# Format the output of git-push, git-show-ref and other commands to make a
> > +# user-friendly and stable text.  We can easily prepare the expect text
> > +# without having to worry about future changes of the commit ID and spaces
> > +# of the output.  We also replce single quotes with double quotes, because
> > +# it is boring to prepare unquoted single quotes in expect txt.
>
> s/txt/text/

Will do. Found it for a long time, but forgot to correct it.

> > +                              (starts_with(ref->name, "refs/tags/")
> > +                               ? "[new tag]"
> > +                               : (starts_with(ref->name, "refs/heads/")
> > +                                  ? "[new branch]"
> > +                                  : "[new reference]")),
> > +                              ref, ref->peer_ref, NULL, porcelain, summary_width);
>
> Now we say "outside refs/heads/ and refs/tags/, that's just a
> reference, different from branch".  OK.
>
> Do we ever update refs/remotes/ with this codepath?  Would we want
> to label it differently, i.e. as "remote-tracking branch"?

Can we call a reference (starts with "refs/remotes/") as a
remote-tracking branch, if it is on the remote side without a proper
remote and branch settings in .git/config?

Thanks.
diff mbox series

Patch

diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh
new file mode 100755
index 0000000000..ef289fe92a
--- /dev/null
+++ b/t/t5411-proc-receive-hook.sh
@@ -0,0 +1,75 @@ 
+#!/bin/sh
+#
+# Copyright (c) 2020 Jiang Xin
+#
+
+test_description='Test proc-receive hook'
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/t5411/common-functions.sh
+
+# Format the output of git-push, git-show-ref and other commands to make a
+# user-friendly and stable text.  In addition to the common format method,
+# we also replace the URL of different protocol for the upstream repository
+# with a fixed pattern.
+make_user_friendly_and_stable_output () {
+	make_user_friendly_and_stable_output_common | sed \
+		-e "s#To ../upstream.git#To <URL/of/upstream.git>#"
+}
+
+# Refs of upstream : master(B)  next(A)
+# Refs of workbench: master(A)           tags/v123
+test_expect_success "setup" '
+	git init --bare upstream.git &&
+	git init workbench &&
+	create_commits_in workbench A B &&
+	(
+		cd workbench &&
+		# Try to make a stable fixed width for abbreviated commit ID,
+		# this fixed-width oid will be replaced with "<OID>".
+		git config core.abbrev 7 &&
+		git remote add origin ../upstream.git &&
+		git update-ref refs/heads/master $A &&
+		git tag -m "v123" v123 $A &&
+		git push origin \
+			$B:refs/heads/master \
+			$A:refs/heads/next
+	) &&
+	TAG=$(git -C workbench rev-parse v123) &&
+
+	# setup pre-receive hook
+	cat >upstream.git/hooks/pre-receive <<-\EOF &&
+	#!/bin/sh
+
+	echo >&2 "# pre-receive hook"
+
+	while read old new ref
+	do
+		echo >&2 "pre-receive< $old $new $ref"
+	done
+	EOF
+
+	# setup post-receive hook
+	cat >upstream.git/hooks/post-receive <<-\EOF &&
+	#!/bin/sh
+
+	echo >&2 "# post-receive hook"
+
+	while read old new ref
+	do
+		echo >&2 "post-receive< $old $new $ref"
+	done
+	EOF
+
+	chmod a+x \
+		upstream.git/hooks/pre-receive \
+		upstream.git/hooks/post-receive &&
+
+	upstream=upstream.git
+'
+
+# Include test cases for both file and HTTP protocol
+. "$TEST_DIRECTORY"/t5411/common-test-cases.sh
+
+test_done
diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh
new file mode 100644
index 0000000000..6e400c0625
--- /dev/null
+++ b/t/t5411/common-functions.sh
@@ -0,0 +1,50 @@ 
+# Create commits in <repo> and assign each commit's oid to shell variables
+# given in the arguments (A, B, and C). E.g.:
+#
+#     create_commits_in <repo> A B C
+#
+# NOTE: Never calling this function from a subshell since variable
+# assignments will disappear when subshell exits.
+create_commits_in () {
+	repo="$1" &&
+	if ! parent=$(git -C "$repo" rev-parse HEAD^{} --)
+	then
+		parent=
+	fi &&
+	T=$(git -C "$repo" write-tree) &&
+	shift &&
+	while test $# -gt 0
+	do
+		name=$1 &&
+		test_tick &&
+		if test -z "$parent"
+		then
+			oid=$(echo $name | git -C "$repo" commit-tree $T)
+		else
+			oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T)
+		fi &&
+		eval $name=$oid &&
+		parent=$oid &&
+		shift ||
+		return 1
+	done &&
+	git -C "$repo" update-ref refs/heads/master $oid
+}
+
+# Format the output of git-push, git-show-ref and other commands to make a
+# user-friendly and stable text.  We can easily prepare the expect text
+# without having to worry about future changes of the commit ID and spaces
+# of the output.  We also replce single quotes with double quotes, because
+# it is boring to prepare unquoted single quotes in expect txt.
+make_user_friendly_and_stable_output_common () {
+	sed \
+		-e "s/  *\$//" \
+		-e "s/   */ /g" \
+		-e "s/'/\"/g" \
+		-e "s/$A/<COMMIT-A>/g" \
+		-e "s/$B/<COMMIT-B>/g" \
+		-e "s/$TAG/<TAG-v123>/g" \
+		-e "s/$ZERO_OID/<ZERO-OID>/g" \
+		-e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \
+		-e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g"
+}
diff --git a/t/t5411/common-test-cases.sh b/t/t5411/common-test-cases.sh
new file mode 100644
index 0000000000..23655846e4
--- /dev/null
+++ b/t/t5411/common-test-cases.sh
@@ -0,0 +1,43 @@ 
+# 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 "normal git-push command" '
+	git -C workbench push -f origin \
+		refs/tags/v123 \
+		:refs/heads/next \
+		HEAD:refs/heads/master \
+		HEAD:refs/review/master/topic \
+		HEAD:refs/heads/a/b/c \
+		>out 2>&1 &&
+	make_user_friendly_and_stable_output <out >actual &&
+	cat >expect <<-EOF &&
+	remote: # pre-receive hook
+	remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+	remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/next
+	remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/master/topic
+	remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
+	remote: # post-receive hook
+	remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+	remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/next
+	remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/master/topic
+	remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
+	To <URL/of/upstream.git>
+	 + <OID-B>...<OID-A> HEAD -> master (forced update)
+	 - [deleted] next
+	 * [new tag] v123 -> v123
+	 * [new reference] HEAD -> refs/review/master/topic
+	 * [new branch] HEAD -> a/b/c
+	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/a/b/c
+	<COMMIT-A> refs/heads/master
+	<COMMIT-A> refs/review/master/topic
+	<TAG-v123> refs/tags/v123
+	EOF
+	test_cmp expect actual
+'
diff --git a/t/t5412-proc-receive-hook-http-protocol.sh b/t/t5412-proc-receive-hook-http-protocol.sh
new file mode 100755
index 0000000000..e2446d4d32
--- /dev/null
+++ b/t/t5412-proc-receive-hook-http-protocol.sh
@@ -0,0 +1,86 @@ 
+#!/bin/sh
+#
+# Copyright (c) 2020 Jiang Xin
+#
+
+test_description='Test proc-receive hook for HTTP protocol'
+
+. ./test-lib.sh
+
+ROOT_PATH="$PWD"
+. "$TEST_DIRECTORY"/lib-gpg.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+start_httpd
+
+. "$TEST_DIRECTORY"/t5411/common-functions.sh
+
+# Format the output of git-push, git-show-ref and other commands to make a
+# user-friendly and stable text.  In addition to the common format method,
+# we also replace the URL of different protocol for the upstream repository
+# with a fixed pattern.
+make_user_friendly_and_stable_output () {
+	make_user_friendly_and_stable_output_common | sed \
+		-e "s#To http:.*/upstream.git#To <URL/of/upstream.git>#"
+}
+
+# Refs of upstream : master(B)  next(A)
+# Refs of workbench: master(A)           tags/v123
+test_expect_success "setup" '
+	git init --bare upstream.git &&
+	git -C upstream.git config http.receivepack true &&
+	git init workbench &&
+	create_commits_in workbench A B &&
+	(
+		cd workbench &&
+		# Try to make a stable fixed width for abbreviated commit ID,
+		# this fixed-width oid will be replaced with "<OID>".
+		git config core.abbrev 7 &&
+		git remote add origin ../upstream.git &&
+		git update-ref refs/heads/master $A &&
+		git tag -m "v123" v123 $A &&
+		git push origin \
+			$B:refs/heads/master \
+			$A:refs/heads/next
+	) &&
+	TAG=$(git -C workbench rev-parse v123) &&
+
+	# setup pre-receive hook
+	cat >upstream.git/hooks/pre-receive <<-\EOF &&
+	#!/bin/sh
+
+	echo >&2 "# pre-receive hook"
+
+	while read old new ref
+	do
+		echo >&2 "pre-receive< $old $new $ref"
+	done
+	EOF
+
+	# setup post-receive hook
+	cat >upstream.git/hooks/post-receive <<-\EOF &&
+	#!/bin/sh
+
+	echo >&2 "# post-receive hook"
+
+	while read old new ref
+	do
+		echo >&2 "post-receive< $old $new $ref"
+	done
+	EOF
+
+	chmod a+x \
+		upstream.git/hooks/pre-receive \
+		upstream.git/hooks/post-receive &&
+
+	upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
+	mv upstream.git "$upstream" &&
+	git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git
+'
+
+setup_askpass_helper
+
+# Include test cases for both file and HTTP protocol
+. "$TEST_DIRECTORY"/t5411/common-test-cases.sh
+
+test_done
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 9ff041a093..9e4b9313b5 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1039,7 +1039,7 @@  test_force_fetch_tag "annotated tag" "-f -a -m'tag message'"
 test_expect_success 'push --porcelain' '
 	mk_empty testrepo &&
 	echo >.git/foo  "To testrepo" &&
-	echo >>.git/foo "*	refs/heads/master:refs/remotes/origin/master	[new branch]"  &&
+	echo >>.git/foo "*	refs/heads/master:refs/remotes/origin/master	[new reference]"  &&
 	echo >>.git/foo "Done" &&
 	git push >.git/bar --porcelain  testrepo refs/heads/master:refs/remotes/origin/master &&
 	(
diff --git a/transport.c b/transport.c
index 1fdc7dac1a..272c0f4046 100644
--- a/transport.c
+++ b/transport.c
@@ -500,9 +500,12 @@  static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt
 				 porcelain, summary_width);
 	else if (is_null_oid(&ref->old_oid))
 		print_ref_status('*',
-			(starts_with(ref->name, "refs/tags/") ? "[new tag]" :
-			"[new branch]"),
-			ref, ref->peer_ref, NULL, porcelain, summary_width);
+				 (starts_with(ref->name, "refs/tags/")
+				  ? "[new tag]"
+				  : (starts_with(ref->name, "refs/heads/")
+				     ? "[new branch]"
+				     : "[new reference]")),
+				 ref, ref->peer_ref, NULL, porcelain, summary_width);
 	else {
 		struct strbuf quickref = STRBUF_INIT;
 		char type;