{"thread":{"id":"59642","subject":"[PATCH] [RFC] transport: add --show-service option","startedAt":"2023-04-24T13:18:03Z","lastAt":"2023-05-10T08:15:16Z","messageCount":6,"participants":["ZheNing Hu via GitGitGadget","Junio C Hamano","ZheNing Hu"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"475912","messageId":"pull.1523.git.1682342241825.gitgitgadget@gmail.com","threadId":"59642","inReplyTo":null,"subject":"[PATCH] [RFC] transport: add --show-service option","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-04-24T13:17:21Z","receivedAt":"2023-04-24T13:18:03Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"From: ZheNing Hu <adlternative@gmail.com>\n\nWithout using protocol v2, the git server needs to send a pktline\n\"# service=$servicename\" to the git client first. This often\nrequires the git server to implement it independently, but it can\nbe delegated to the `git receive-pack` and `git upload-pack` to complete\nthe work proactively. Therefore, the `--show-service` option is added\nto `git receive-pack` and `git upload-pack`, which can be used to send\nthe \"# service=$servicename\" pktline, making the logic of the git\nserver more concise.\n\nNote that this `--show-service` option can only be used together with\n`--http-backend-info-refs` and it is not applicable when using protocol v2.\n\nSigned-off-by: ZheNing Hu <adlternative@gmail.com>\n---\n    [RFC] transport: add --show-service option\n    \n    When the protocol is not v2, the git client requires that the first\n    pktline reply for info refs be \"# service=servicename\", which requires\n    the git server to implement pktline capability, e.g. [1] , which may be\n    a bit cumbersome.\n    \n    Delegating this feature to git upload-pack and git receive-pack via\n    \"--show-service\" can simplify server implementation.\n    \n    v1. add --show-service to git upload-pack and git receive-pack.\n    \n    [1]:\n    https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1523%2Fadlternative%2Fzh%2Finfo-ref-service-output-opt-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1523/adlternative/zh/info-ref-service-output-opt-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1523\n\n Documentation/git-receive-pack.txt |  10 +++\n Documentation/git-upload-pack.txt  |  13 +++-\n builtin/receive-pack.c             |  14 +++-\n builtin/upload-pack.c              |  17 +++-\n http-backend.c                     |   7 +-\n t/t5555-http-smart-common.sh       | 120 +++++++++++++++++++++++++++++\n 6 files changed, 171 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt\nindex 65ff518ccff..e16d364f394 100644\n--- a/Documentation/git-receive-pack.txt\n+++ b/Documentation/git-receive-pack.txt\n@@ -46,6 +46,16 @@ OPTIONS\n \t`$GIT_URL/info/refs?service=git-receive-pack` requests. See\n \t`--http-backend-info-refs` in linkgit:git-upload-pack[1].\n \n+--show-service::\n+\tOutput the \"# service=git-receive-pack\" pktline and the\n+\t\"0000\" flush pktline firstly. Since the git client needs\n+\tthe git server to send the first pktline\n+\t\"# service=$servicename\", this option allows the git\n+\tserver to delegate the functionality of sending this pktline\n+\tto `git-receive-pack`.\n+\tNote that this option can only be used together with\n+\t`--http-backend-info-refs`.\n+\n PRE-RECEIVE HOOK\n ----------------\n Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists\ndiff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt\nindex b656b475675..7052708d03e 100644\n--- a/Documentation/git-upload-pack.txt\n+++ b/Documentation/git-upload-pack.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n-\t\t  [--advertise-refs] <directory>\n+\t\t  [--advertise-refs] [--show-service] <directory>\n \n DESCRIPTION\n -----------\n@@ -44,6 +44,17 @@ OPTIONS\n \tdocumentation. Also understood by\n \tlinkgit:git-receive-pack[1].\n \n+--show-service::\n+\tOutput the \"# service=git-upload-pack\" pktline and the\n+\t\"0000\" flush pktline firstly. Since the git client needs\n+\tthe git server to send the first pktline\n+\t\"# service=$servicename\", this option allows the git\n+\tserver to delegate the functionality of sending this pktline\n+\tto `git-upload-pack`.\n+\tNote that this option can only be used together with\n+\t`--http-backend-info-refs` and it is not applicable when\n+\tusing protocol v2.\n+\n <directory>::\n \tThe repository to sync from.\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 9109552533d..eb45c1f72af 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -2485,6 +2485,7 @@ static int delete_only(struct command *commands)\n int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n {\n \tint advertise_refs = 0;\n+\tint show_service = 0;\n \tstruct command *commands;\n \tstruct oid_array shallow = OID_ARRAY_INIT;\n \tstruct oid_array ref = OID_ARRAY_INIT;\n@@ -2497,8 +2498,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n \t\tOPT_HIDDEN_BOOL(0, \"http-backend-info-refs\", &advertise_refs, NULL),\n \t\tOPT_ALIAS(0, \"advertise-refs\", \"http-backend-info-refs\"),\n \t\tOPT_HIDDEN_BOOL(0, \"reject-thin-pack-for-testing\", &reject_thin, NULL),\n+\t\tOPT_BOOL(0, \"show-service\", &show_service, N_(\"show service information\")),\n \t\tOPT_END()\n \t};\n+\tenum protocol_version version = determine_protocol_version_server();\n \n \tpacket_trace_identity(\"receive-pack\");\n \n@@ -2525,7 +2528,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n \telse if (0 <= receive_unpack_limit)\n \t\tunpack_limit = receive_unpack_limit;\n \n-\tswitch (determine_protocol_version_server()) {\n+\tif (show_service) {\n+\t\tif (!advertise_refs)\n+\t\t\tdie(_(\"options '%s' and '%s' should be used together\"), \"--show-service\", \"--http-backend-info-refs\");\n+\t\tif (version != protocol_v2) {\n+\t\t\tpacket_write_fmt(1, \"# service=git-receive-pack\\n\");\n+\t\t\tpacket_flush(1);\n+\t\t}\n+\t}\n+\n+\tswitch (version) {\n \tcase protocol_v2:\n \t\t/*\n \t\t * push support for protocol v2 has not been implemented yet,\ndiff --git a/builtin/upload-pack.c b/builtin/upload-pack.c\nindex beb9dd08610..e84eb3735b4 100644\n--- a/builtin/upload-pack.c\n+++ b/builtin/upload-pack.c\n@@ -11,7 +11,7 @@\n \n static const char * const upload_pack_usage[] = {\n \tN_(\"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\\n\"\n-\t   \"                [--advertise-refs] <directory>\"),\n+\t   \"                [--advertise-refs] [--show-service] <directory>\"),\n \tNULL\n };\n \n@@ -22,6 +22,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n \tint advertise_refs = 0;\n \tint stateless_rpc = 0;\n \tint timeout = 0;\n+\tint show_service = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"stateless-rpc\", &stateless_rpc,\n \t\t\t N_(\"quit after a single request/response exchange\")),\n@@ -32,8 +33,10 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"do not try <directory>/.git/ if <directory> is no Git directory\")),\n \t\tOPT_INTEGER(0, \"timeout\", &timeout,\n \t\t\t    N_(\"interrupt transfer after <n> seconds of inactivity\")),\n+\t\tOPT_BOOL(0, \"show-service\", &show_service, N_(\"show service information\")),\n \t\tOPT_END()\n \t};\n+\tenum protocol_version version = determine_protocol_version_server();\n \n \tpacket_trace_identity(\"upload-pack\");\n \tread_replace_refs = 0;\n@@ -50,7 +53,17 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n \tif (!enter_repo(dir, strict))\n \t\tdie(\"'%s' does not appear to be a git repository\", dir);\n \n-\tswitch (determine_protocol_version_server()) {\n+\n+\tif (show_service) {\n+\t\tif (!advertise_refs)\n+\t\t\tdie(_(\"options '%s' and '%s' should be used together\"), \"--show-service\", \"--http-backend-info-refs\");\n+\t\tif (version != protocol_v2) {\n+\t\t\tpacket_write_fmt(1, \"# service=git-upload-pack\\n\");\n+\t\t\tpacket_flush(1);\n+\t\t}\n+\t}\n+\n+\tswitch (version) {\n \tcase protocol_v2:\n \t\tif (advertise_refs)\n \t\t\tprotocol_v2_advertise_capabilities();\ndiff --git a/http-backend.c b/http-backend.c\nindex 89aad1b42c7..74c2c7bb606 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -539,6 +539,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)\n \tif (service_name) {\n \t\tconst char *argv[] = {NULL /* service name */,\n \t\t\t\"--http-backend-info-refs\",\n+\t\t\t\"--show-service\",\n \t\t\t\".\", NULL};\n \t\tstruct rpc_service *svc = select_service(hdr, service_name);\n \n@@ -547,12 +548,6 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)\n \t\thdr_str(hdr, content_type, buf.buf);\n \t\tend_headers(hdr);\n \n-\n-\t\tif (determine_protocol_version_server() != protocol_v2) {\n-\t\t\tpacket_write_fmt(1, \"# service=git-%s\\n\", svc->name);\n-\t\t\tpacket_flush(1);\n-\t\t}\n-\n \t\targv[0] = svc->name;\n \t\trun_service(argv, 0);\n \ndiff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh\nindex b1cfe8b7dba..32431266eb9 100755\n--- a/t/t5555-http-smart-common.sh\n+++ b/t/t5555-http-smart-common.sh\n@@ -159,4 +159,124 @@ test_expect_success 'git receive-pack --advertise-refs: v2' '\n \ttest_cmp actual expect\n '\n \n+test_expect_success 'git upload-pack --advertise-refs --show-service: v0' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-upload-pack\n+\t0000\n+\t$(git rev-parse HEAD) HEAD\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tgit upload-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect &&\n+\n+\t# With explicit v0\n+\tGIT_PROTOCOL=version=0 \\\n+\tgit upload-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+\n+'\n+\n+test_expect_success 'git receive-pack --advertise-refs --show-service: v0' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-receive-pack\n+\t0000\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tgit receive-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect &&\n+\n+\t# With explicit v0\n+\tGIT_PROTOCOL=version=0 \\\n+\tgit receive-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+\n+'\n+\n+test_expect_success 'git upload-pack --advertise-refs --show-service: v1' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-upload-pack\n+\t0000\n+\tversion 1\n+\t$(git rev-parse HEAD) HEAD\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=1 \\\n+\tgit upload-pack --advertise-refs --show-service . >out &&\n+\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n+test_expect_success 'git receive-pack --advertise-refs --show-service: v1' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-receive-pack\n+\t0000\n+\tversion 1\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=1 \\\n+\tgit receive-pack --advertise-refs --show-service . >out &&\n+\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n+test_expect_success 'git upload-pack --advertise-refs --show-service: v2' '\n+\tcat >expect <<-EOF &&\n+\tversion 2\n+\tagent=FAKE\n+\tls-refs=unborn\n+\tfetch=shallow wait-for-done\n+\tserver-option\n+\tobject-format=$(test_oid algo)\n+\tobject-info\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=2 \\\n+\tGIT_USER_AGENT=FAKE \\\n+\tgit upload-pack --advertise-refs --show-service . >out 2>err &&\n+\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n+test_expect_success 'git receive-pack --advertise-refs --show-service: v2' '\n+\t# There is no v2 yet for receive-pack, implicit v0\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=2 \\\n+\tgit receive-pack --advertise-refs --show-service . >out 2>err &&\n+\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n test_done\n\nbase-commit: 7580f92ffa970b9484ac214f7b53cec5e26ca4bc\n-- \ngitgitgadget\n"},{"id":"476001","messageId":"xmqq354o8v8u.fsf@gitster.g","threadId":"59642","inReplyTo":"pull.1523.git.1682342241825.gitgitgadget@gmail.com","subject":"Re: [PATCH] [RFC] transport: add --show-service option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-04-25T04:02:25Z","receivedAt":"2023-04-25T04:02:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"ZheNing Hu via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: ZheNing Hu <adlternative@gmail.com>\n>\n> Without using protocol v2, the git server needs to send a pktline\n> \"# service=$servicename\" to the git client first. This often\n> requires the git server to implement it independently, but it can\n> be delegated to the `git receive-pack` and `git upload-pack` to complete\n> the work proactively. Therefore, the `--show-service` option is added\n> to `git receive-pack` and `git upload-pack`, which can be used to send\n> the \"# service=$servicename\" pktline, making the logic of the git\n> server more concise.\n>\n> Note that this `--show-service` option can only be used together with\n> `--http-backend-info-refs` and it is not applicable when using protocol v2.\n>\n> Signed-off-by: ZheNing Hu <adlternative@gmail.com>\n> ---\n\nThe above is a very well written description of why we _can_ do\nthis, but it is unclear why we would _want_ to do this.  What do we\ngain by letting the individual services to declare \"we are serving\nthis!\"?  Do we lose an extra fork & process (it does not seem to be\nthe case)?\n"},{"id":"476162","messageId":"CAOLTT8Qmo31YExXUOPk2sx73b734wuxiD3AUX0UAnPo9WSqpfQ@mail.gmail.com","threadId":"59642","inReplyTo":"xmqq354o8v8u.fsf@gitster.g","subject":"Re: [PATCH] [RFC] transport: add --show-service option","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2023-04-27T04:35:23Z","receivedAt":"2023-04-27T04:34:58Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Junio C Hamano <gitster@pobox.com> 于2023年4月25日周二 12:02写道：\n>\n> \"ZheNing Hu via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n> > From: ZheNing Hu <adlternative@gmail.com>\n> >\n> > Without using protocol v2, the git server needs to send a pktline\n> > \"# service=$servicename\" to the git client first. This often\n> > requires the git server to implement it independently, but it can\n> > be delegated to the `git receive-pack` and `git upload-pack` to complete\n> > the work proactively. Therefore, the `--show-service` option is added\n> > to `git receive-pack` and `git upload-pack`, which can be used to send\n> > the \"# service=$servicename\" pktline, making the logic of the git\n> > server more concise.\n> >\n> > Note that this `--show-service` option can only be used together with\n> > `--http-backend-info-refs` and it is not applicable when using protocol v2.\n> >\n> > Signed-off-by: ZheNing Hu <adlternative@gmail.com>\n> > ---\n>\n> The above is a very well written description of why we _can_ do\n> this, but it is unclear why we would _want_ to do this.  What do we\n> gain by letting the individual services to declare \"we are serving\n> this!\"?  Do we lose an extra fork & process (it does not seem to be\n> the case)?\n\nWhen I was implementing a small git http server, I wanted to delegate\neverything to upload-pack and receive-pack. Everything else was fine,\nthe only thing I was not satisfied with was the need to send an additional\n\"#service=$servername\" message when the protocol is v1. To be honest,\nthe $servername here can only be \"git-upload-pack\" and \"git-receive-pack\",\nand the git client does not actually do anything extra with this message.\nWhy not let git upload-pack and git receive-pack do it?\n\nThe \"--show-service\" option is not a functional requirement, it just\nsimplifies the logic of the git server.\n"},{"id":"476170","messageId":"xmqqsfclnaaz.fsf@gitster.g","threadId":"59642","inReplyTo":"CAOLTT8Qmo31YExXUOPk2sx73b734wuxiD3AUX0UAnPo9WSqpfQ@mail.gmail.com","subject":"Re: [PATCH] [RFC] transport: add --show-service option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-04-27T05:50:12Z","receivedAt":"2023-04-27T05:50:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"ZheNing Hu <adlternative@gmail.com> writes:\n\n>> The above is a very well written description of why we _can_ do\n>> this, but it is unclear why we would _want_ to do this.  What do we\n>> gain by letting the individual services to declare \"we are serving\n>> this!\"?  Do we lose an extra fork & process (it does not seem to be\n>> the case)?\n>\n> When I was implementing a small git http server, I wanted to delegate\n> everything to upload-pack and receive-pack. Everything else was fine,\n> the only thing I was not satisfied with was the need to send an additional\n> \"#service=$servername\" message when the protocol is v1.\n\nI think you had a brief mention on that after the three-dash separator;\nit *is* a relevant piece of information that needs to be in the\nproposed log message.\n\nThanks.\n"},{"id":"476596","messageId":"pull.1523.v2.git.1683214104399.gitgitgadget@gmail.com","threadId":"59642","inReplyTo":"pull.1523.git.1682342241825.gitgitgadget@gmail.com","subject":"[PATCH v2] [RFC] transport: add --show-service option","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-05-04T15:28:23Z","receivedAt":"2023-05-04T15:28:36Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"From: ZheNing Hu <adlternative@gmail.com>\n\nWithout using protocol v2, the git server needs to send a pktline\n\"#service=$servicename\" to the git client first. The servername\nhere can only be selected in \"git-receive-pack and \"git-upload-pack\",\nneither the git client nor the server depends on this servername to\nperform any functions. Howerver, , implementing this capability\nindependently can be cumbersome for the git server, as seen in [1].\n\nTo simplify this process, the `--show-service` option was added to\ngit-receive-pack and git-upload-pack. This option can be used to\nsend the '#service=$servicename' pktline, making the logic of the\ngit server more concise. Note that this option can only be used\ntogether with --http-backend-info-refs and is not applicable when\nusing protocol v2.\n\n[1]: https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n\nSigned-off-by: ZheNing Hu <adlternative@gmail.com>\n---\n    [RFC] transport: add --show-service option\n    \n    When the protocol is not v2, the git client requires that the first\n    pktline reply for info refs be \"# service=servicename\", which requires\n    the git server to implement pktline capability, e.g. [1] , which may be\n    a bit cumbersome.\n    \n    Delegating this feature to git upload-pack and git receive-pack via\n    \"--show-service\" can simplify server implementation.\n    \n    v1. add --show-service to git upload-pack and git receive-pack. v2.\n    amend the git commit message to explain the reason for adding the\n    option.\n    \n    [1]:\n    https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1523%2Fadlternative%2Fzh%2Finfo-ref-service-output-opt-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1523/adlternative/zh/info-ref-service-output-opt-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1523\n\nRange-diff vs v1:\n\n 1:  a2d33d6857a ! 1:  b8aa0e7e053 [RFC] transport: add --show-service option\n     @@ Commit message\n          [RFC] transport: add --show-service option\n      \n          Without using protocol v2, the git server needs to send a pktline\n     -    \"# service=$servicename\" to the git client first. This often\n     -    requires the git server to implement it independently, but it can\n     -    be delegated to the `git receive-pack` and `git upload-pack` to complete\n     -    the work proactively. Therefore, the `--show-service` option is added\n     -    to `git receive-pack` and `git upload-pack`, which can be used to send\n     -    the \"# service=$servicename\" pktline, making the logic of the git\n     -    server more concise.\n     +    \"#service=$servicename\" to the git client first. The servername\n     +    here can only be selected in \"git-receive-pack and \"git-upload-pack\",\n     +    neither the git client nor the server depends on this servername to\n     +    perform any functions. Howerver, , implementing this capability\n     +    independently can be cumbersome for the git server, as seen in [1].\n      \n     -    Note that this `--show-service` option can only be used together with\n     -    `--http-backend-info-refs` and it is not applicable when using protocol v2.\n     +    To simplify this process, the `--show-service` option was added to\n     +    git-receive-pack and git-upload-pack. This option can be used to\n     +    send the '#service=$servicename' pktline, making the logic of the\n     +    git server more concise. Note that this option can only be used\n     +    together with --http-backend-info-refs and is not applicable when\n     +    using protocol v2.\n     +\n     +    [1]: https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n      \n          Signed-off-by: ZheNing Hu <adlternative@gmail.com>\n      \n\n\n Documentation/git-receive-pack.txt |  10 +++\n Documentation/git-upload-pack.txt  |  13 +++-\n builtin/receive-pack.c             |  14 +++-\n builtin/upload-pack.c              |  17 +++-\n http-backend.c                     |   7 +-\n t/t5555-http-smart-common.sh       | 120 +++++++++++++++++++++++++++++\n 6 files changed, 171 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt\nindex 65ff518ccff..e16d364f394 100644\n--- a/Documentation/git-receive-pack.txt\n+++ b/Documentation/git-receive-pack.txt\n@@ -46,6 +46,16 @@ OPTIONS\n \t`$GIT_URL/info/refs?service=git-receive-pack` requests. See\n \t`--http-backend-info-refs` in linkgit:git-upload-pack[1].\n \n+--show-service::\n+\tOutput the \"# service=git-receive-pack\" pktline and the\n+\t\"0000\" flush pktline firstly. Since the git client needs\n+\tthe git server to send the first pktline\n+\t\"# service=$servicename\", this option allows the git\n+\tserver to delegate the functionality of sending this pktline\n+\tto `git-receive-pack`.\n+\tNote that this option can only be used together with\n+\t`--http-backend-info-refs`.\n+\n PRE-RECEIVE HOOK\n ----------------\n Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists\ndiff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt\nindex b656b475675..7052708d03e 100644\n--- a/Documentation/git-upload-pack.txt\n+++ b/Documentation/git-upload-pack.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n-\t\t  [--advertise-refs] <directory>\n+\t\t  [--advertise-refs] [--show-service] <directory>\n \n DESCRIPTION\n -----------\n@@ -44,6 +44,17 @@ OPTIONS\n \tdocumentation. Also understood by\n \tlinkgit:git-receive-pack[1].\n \n+--show-service::\n+\tOutput the \"# service=git-upload-pack\" pktline and the\n+\t\"0000\" flush pktline firstly. Since the git client needs\n+\tthe git server to send the first pktline\n+\t\"# service=$servicename\", this option allows the git\n+\tserver to delegate the functionality of sending this pktline\n+\tto `git-upload-pack`.\n+\tNote that this option can only be used together with\n+\t`--http-backend-info-refs` and it is not applicable when\n+\tusing protocol v2.\n+\n <directory>::\n \tThe repository to sync from.\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 9109552533d..eb45c1f72af 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -2485,6 +2485,7 @@ static int delete_only(struct command *commands)\n int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n {\n \tint advertise_refs = 0;\n+\tint show_service = 0;\n \tstruct command *commands;\n \tstruct oid_array shallow = OID_ARRAY_INIT;\n \tstruct oid_array ref = OID_ARRAY_INIT;\n@@ -2497,8 +2498,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n \t\tOPT_HIDDEN_BOOL(0, \"http-backend-info-refs\", &advertise_refs, NULL),\n \t\tOPT_ALIAS(0, \"advertise-refs\", \"http-backend-info-refs\"),\n \t\tOPT_HIDDEN_BOOL(0, \"reject-thin-pack-for-testing\", &reject_thin, NULL),\n+\t\tOPT_BOOL(0, \"show-service\", &show_service, N_(\"show service information\")),\n \t\tOPT_END()\n \t};\n+\tenum protocol_version version = determine_protocol_version_server();\n \n \tpacket_trace_identity(\"receive-pack\");\n \n@@ -2525,7 +2528,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n \telse if (0 <= receive_unpack_limit)\n \t\tunpack_limit = receive_unpack_limit;\n \n-\tswitch (determine_protocol_version_server()) {\n+\tif (show_service) {\n+\t\tif (!advertise_refs)\n+\t\t\tdie(_(\"options '%s' and '%s' should be used together\"), \"--show-service\", \"--http-backend-info-refs\");\n+\t\tif (version != protocol_v2) {\n+\t\t\tpacket_write_fmt(1, \"# service=git-receive-pack\\n\");\n+\t\t\tpacket_flush(1);\n+\t\t}\n+\t}\n+\n+\tswitch (version) {\n \tcase protocol_v2:\n \t\t/*\n \t\t * push support for protocol v2 has not been implemented yet,\ndiff --git a/builtin/upload-pack.c b/builtin/upload-pack.c\nindex beb9dd08610..e84eb3735b4 100644\n--- a/builtin/upload-pack.c\n+++ b/builtin/upload-pack.c\n@@ -11,7 +11,7 @@\n \n static const char * const upload_pack_usage[] = {\n \tN_(\"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\\n\"\n-\t   \"                [--advertise-refs] <directory>\"),\n+\t   \"                [--advertise-refs] [--show-service] <directory>\"),\n \tNULL\n };\n \n@@ -22,6 +22,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n \tint advertise_refs = 0;\n \tint stateless_rpc = 0;\n \tint timeout = 0;\n+\tint show_service = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"stateless-rpc\", &stateless_rpc,\n \t\t\t N_(\"quit after a single request/response exchange\")),\n@@ -32,8 +33,10 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"do not try <directory>/.git/ if <directory> is no Git directory\")),\n \t\tOPT_INTEGER(0, \"timeout\", &timeout,\n \t\t\t    N_(\"interrupt transfer after <n> seconds of inactivity\")),\n+\t\tOPT_BOOL(0, \"show-service\", &show_service, N_(\"show service information\")),\n \t\tOPT_END()\n \t};\n+\tenum protocol_version version = determine_protocol_version_server();\n \n \tpacket_trace_identity(\"upload-pack\");\n \tread_replace_refs = 0;\n@@ -50,7 +53,17 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n \tif (!enter_repo(dir, strict))\n \t\tdie(\"'%s' does not appear to be a git repository\", dir);\n \n-\tswitch (determine_protocol_version_server()) {\n+\n+\tif (show_service) {\n+\t\tif (!advertise_refs)\n+\t\t\tdie(_(\"options '%s' and '%s' should be used together\"), \"--show-service\", \"--http-backend-info-refs\");\n+\t\tif (version != protocol_v2) {\n+\t\t\tpacket_write_fmt(1, \"# service=git-upload-pack\\n\");\n+\t\t\tpacket_flush(1);\n+\t\t}\n+\t}\n+\n+\tswitch (version) {\n \tcase protocol_v2:\n \t\tif (advertise_refs)\n \t\t\tprotocol_v2_advertise_capabilities();\ndiff --git a/http-backend.c b/http-backend.c\nindex 89aad1b42c7..74c2c7bb606 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -539,6 +539,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)\n \tif (service_name) {\n \t\tconst char *argv[] = {NULL /* service name */,\n \t\t\t\"--http-backend-info-refs\",\n+\t\t\t\"--show-service\",\n \t\t\t\".\", NULL};\n \t\tstruct rpc_service *svc = select_service(hdr, service_name);\n \n@@ -547,12 +548,6 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)\n \t\thdr_str(hdr, content_type, buf.buf);\n \t\tend_headers(hdr);\n \n-\n-\t\tif (determine_protocol_version_server() != protocol_v2) {\n-\t\t\tpacket_write_fmt(1, \"# service=git-%s\\n\", svc->name);\n-\t\t\tpacket_flush(1);\n-\t\t}\n-\n \t\targv[0] = svc->name;\n \t\trun_service(argv, 0);\n \ndiff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh\nindex b1cfe8b7dba..32431266eb9 100755\n--- a/t/t5555-http-smart-common.sh\n+++ b/t/t5555-http-smart-common.sh\n@@ -159,4 +159,124 @@ test_expect_success 'git receive-pack --advertise-refs: v2' '\n \ttest_cmp actual expect\n '\n \n+test_expect_success 'git upload-pack --advertise-refs --show-service: v0' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-upload-pack\n+\t0000\n+\t$(git rev-parse HEAD) HEAD\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tgit upload-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect &&\n+\n+\t# With explicit v0\n+\tGIT_PROTOCOL=version=0 \\\n+\tgit upload-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+\n+'\n+\n+test_expect_success 'git receive-pack --advertise-refs --show-service: v0' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-receive-pack\n+\t0000\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tgit receive-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect &&\n+\n+\t# With explicit v0\n+\tGIT_PROTOCOL=version=0 \\\n+\tgit receive-pack --advertise-refs --show-service . >out 2>err &&\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+\n+'\n+\n+test_expect_success 'git upload-pack --advertise-refs --show-service: v1' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-upload-pack\n+\t0000\n+\tversion 1\n+\t$(git rev-parse HEAD) HEAD\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=1 \\\n+\tgit upload-pack --advertise-refs --show-service . >out &&\n+\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n+test_expect_success 'git receive-pack --advertise-refs --show-service: v1' '\n+\t# With no specified protocol\n+\tcat >expect <<-EOF &&\n+\t# service=git-receive-pack\n+\t0000\n+\tversion 1\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=1 \\\n+\tgit receive-pack --advertise-refs --show-service . >out &&\n+\n+\ttest-tool pkt-line unpack <out >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n+test_expect_success 'git upload-pack --advertise-refs --show-service: v2' '\n+\tcat >expect <<-EOF &&\n+\tversion 2\n+\tagent=FAKE\n+\tls-refs=unborn\n+\tfetch=shallow wait-for-done\n+\tserver-option\n+\tobject-format=$(test_oid algo)\n+\tobject-info\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=2 \\\n+\tGIT_USER_AGENT=FAKE \\\n+\tgit upload-pack --advertise-refs --show-service . >out 2>err &&\n+\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n+test_expect_success 'git receive-pack --advertise-refs --show-service: v2' '\n+\t# There is no v2 yet for receive-pack, implicit v0\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse HEAD) $(git symbolic-ref HEAD)\n+\t0000\n+\tEOF\n+\n+\tGIT_PROTOCOL=version=2 \\\n+\tgit receive-pack --advertise-refs --show-service . >out 2>err &&\n+\n+\ttest-tool pkt-line unpack <out >actual &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp actual expect\n+'\n+\n test_done\n\nbase-commit: 7580f92ffa970b9484ac214f7b53cec5e26ca4bc\n-- \ngitgitgadget\n"},{"id":"476954","messageId":"CAOLTT8SA9MvGTJojYFzD=LtPG=WMdEwK-ufgTyHwhCEDRFG=yQ@mail.gmail.com","threadId":"59642","inReplyTo":"pull.1523.v2.git.1683214104399.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] [RFC] transport: add --show-service option","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2023-05-10T08:15:58Z","receivedAt":"2023-05-10T08:15:16Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Just ping for this patch...\n\nZheNing Hu via GitGitGadget <gitgitgadget@gmail.com> 于2023年5月4日周四 23:28写道：\n>\n> From: ZheNing Hu <adlternative@gmail.com>\n>\n> Without using protocol v2, the git server needs to send a pktline\n> \"#service=$servicename\" to the git client first. The servername\n> here can only be selected in \"git-receive-pack and \"git-upload-pack\",\n> neither the git client nor the server depends on this servername to\n> perform any functions. Howerver, , implementing this capability\n> independently can be cumbersome for the git server, as seen in [1].\n>\n> To simplify this process, the `--show-service` option was added to\n> git-receive-pack and git-upload-pack. This option can be used to\n> send the '#service=$servicename' pktline, making the logic of the\n> git server more concise. Note that this option can only be used\n> together with --http-backend-info-refs and is not applicable when\n> using protocol v2.\n>\n> [1]: https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n>\n> Signed-off-by: ZheNing Hu <adlternative@gmail.com>\n> ---\n>     [RFC] transport: add --show-service option\n>\n>     When the protocol is not v2, the git client requires that the first\n>     pktline reply for info refs be \"# service=servicename\", which requires\n>     the git server to implement pktline capability, e.g. [1] , which may be\n>     a bit cumbersome.\n>\n>     Delegating this feature to git upload-pack and git receive-pack via\n>     \"--show-service\" can simplify server implementation.\n>\n>     v1. add --show-service to git upload-pack and git receive-pack. v2.\n>     amend the git commit message to explain the reason for adding the\n>     option.\n>\n>     [1]:\n>     https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n>\n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1523%2Fadlternative%2Fzh%2Finfo-ref-service-output-opt-v2\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1523/adlternative/zh/info-ref-service-output-opt-v2\n> Pull-Request: https://github.com/gitgitgadget/git/pull/1523\n>\n> Range-diff vs v1:\n>\n>  1:  a2d33d6857a ! 1:  b8aa0e7e053 [RFC] transport: add --show-service option\n>      @@ Commit message\n>           [RFC] transport: add --show-service option\n>\n>           Without using protocol v2, the git server needs to send a pktline\n>      -    \"# service=$servicename\" to the git client first. This often\n>      -    requires the git server to implement it independently, but it can\n>      -    be delegated to the `git receive-pack` and `git upload-pack` to complete\n>      -    the work proactively. Therefore, the `--show-service` option is added\n>      -    to `git receive-pack` and `git upload-pack`, which can be used to send\n>      -    the \"# service=$servicename\" pktline, making the logic of the git\n>      -    server more concise.\n>      +    \"#service=$servicename\" to the git client first. The servername\n>      +    here can only be selected in \"git-receive-pack and \"git-upload-pack\",\n>      +    neither the git client nor the server depends on this servername to\n>      +    perform any functions. Howerver, , implementing this capability\n>      +    independently can be cumbersome for the git server, as seen in [1].\n>\n>      -    Note that this `--show-service` option can only be used together with\n>      -    `--http-backend-info-refs` and it is not applicable when using protocol v2.\n>      +    To simplify this process, the `--show-service` option was added to\n>      +    git-receive-pack and git-upload-pack. This option can be used to\n>      +    send the '#service=$servicename' pktline, making the logic of the\n>      +    git server more concise. Note that this option can only be used\n>      +    together with --http-backend-info-refs and is not applicable when\n>      +    using protocol v2.\n>      +\n>      +    [1]: https://gitlab.com/gitlab-org/gitaly/-/blob/master/internal/gitaly/service/smarthttp/inforefs.go#L82\n>\n>           Signed-off-by: ZheNing Hu <adlternative@gmail.com>\n>\n>\n>\n>  Documentation/git-receive-pack.txt |  10 +++\n>  Documentation/git-upload-pack.txt  |  13 +++-\n>  builtin/receive-pack.c             |  14 +++-\n>  builtin/upload-pack.c              |  17 +++-\n>  http-backend.c                     |   7 +-\n>  t/t5555-http-smart-common.sh       | 120 +++++++++++++++++++++++++++++\n>  6 files changed, 171 insertions(+), 10 deletions(-)\n>\n> diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt\n> index 65ff518ccff..e16d364f394 100644\n> --- a/Documentation/git-receive-pack.txt\n> +++ b/Documentation/git-receive-pack.txt\n> @@ -46,6 +46,16 @@ OPTIONS\n>         `$GIT_URL/info/refs?service=git-receive-pack` requests. See\n>         `--http-backend-info-refs` in linkgit:git-upload-pack[1].\n>\n> +--show-service::\n> +       Output the \"# service=git-receive-pack\" pktline and the\n> +       \"0000\" flush pktline firstly. Since the git client needs\n> +       the git server to send the first pktline\n> +       \"# service=$servicename\", this option allows the git\n> +       server to delegate the functionality of sending this pktline\n> +       to `git-receive-pack`.\n> +       Note that this option can only be used together with\n> +       `--http-backend-info-refs`.\n> +\n>  PRE-RECEIVE HOOK\n>  ----------------\n>  Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists\n> diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt\n> index b656b475675..7052708d03e 100644\n> --- a/Documentation/git-upload-pack.txt\n> +++ b/Documentation/git-upload-pack.txt\n> @@ -10,7 +10,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n> -                 [--advertise-refs] <directory>\n> +                 [--advertise-refs] [--show-service] <directory>\n>\n>  DESCRIPTION\n>  -----------\n> @@ -44,6 +44,17 @@ OPTIONS\n>         documentation. Also understood by\n>         linkgit:git-receive-pack[1].\n>\n> +--show-service::\n> +       Output the \"# service=git-upload-pack\" pktline and the\n> +       \"0000\" flush pktline firstly. Since the git client needs\n> +       the git server to send the first pktline\n> +       \"# service=$servicename\", this option allows the git\n> +       server to delegate the functionality of sending this pktline\n> +       to `git-upload-pack`.\n> +       Note that this option can only be used together with\n> +       `--http-backend-info-refs` and it is not applicable when\n> +       using protocol v2.\n> +\n>  <directory>::\n>         The repository to sync from.\n>\n> diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\n> index 9109552533d..eb45c1f72af 100644\n> --- a/builtin/receive-pack.c\n> +++ b/builtin/receive-pack.c\n> @@ -2485,6 +2485,7 @@ static int delete_only(struct command *commands)\n>  int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n>  {\n>         int advertise_refs = 0;\n> +       int show_service = 0;\n>         struct command *commands;\n>         struct oid_array shallow = OID_ARRAY_INIT;\n>         struct oid_array ref = OID_ARRAY_INIT;\n> @@ -2497,8 +2498,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n>                 OPT_HIDDEN_BOOL(0, \"http-backend-info-refs\", &advertise_refs, NULL),\n>                 OPT_ALIAS(0, \"advertise-refs\", \"http-backend-info-refs\"),\n>                 OPT_HIDDEN_BOOL(0, \"reject-thin-pack-for-testing\", &reject_thin, NULL),\n> +               OPT_BOOL(0, \"show-service\", &show_service, N_(\"show service information\")),\n>                 OPT_END()\n>         };\n> +       enum protocol_version version = determine_protocol_version_server();\n>\n>         packet_trace_identity(\"receive-pack\");\n>\n> @@ -2525,7 +2528,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)\n>         else if (0 <= receive_unpack_limit)\n>                 unpack_limit = receive_unpack_limit;\n>\n> -       switch (determine_protocol_version_server()) {\n> +       if (show_service) {\n> +               if (!advertise_refs)\n> +                       die(_(\"options '%s' and '%s' should be used together\"), \"--show-service\", \"--http-backend-info-refs\");\n> +               if (version != protocol_v2) {\n> +                       packet_write_fmt(1, \"# service=git-receive-pack\\n\");\n> +                       packet_flush(1);\n> +               }\n> +       }\n> +\n> +       switch (version) {\n>         case protocol_v2:\n>                 /*\n>                  * push support for protocol v2 has not been implemented yet,\n> diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c\n> index beb9dd08610..e84eb3735b4 100644\n> --- a/builtin/upload-pack.c\n> +++ b/builtin/upload-pack.c\n> @@ -11,7 +11,7 @@\n>\n>  static const char * const upload_pack_usage[] = {\n>         N_(\"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\\n\"\n> -          \"                [--advertise-refs] <directory>\"),\n> +          \"                [--advertise-refs] [--show-service] <directory>\"),\n>         NULL\n>  };\n>\n> @@ -22,6 +22,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n>         int advertise_refs = 0;\n>         int stateless_rpc = 0;\n>         int timeout = 0;\n> +       int show_service = 0;\n>         struct option options[] = {\n>                 OPT_BOOL(0, \"stateless-rpc\", &stateless_rpc,\n>                          N_(\"quit after a single request/response exchange\")),\n> @@ -32,8 +33,10 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n>                          N_(\"do not try <directory>/.git/ if <directory> is no Git directory\")),\n>                 OPT_INTEGER(0, \"timeout\", &timeout,\n>                             N_(\"interrupt transfer after <n> seconds of inactivity\")),\n> +               OPT_BOOL(0, \"show-service\", &show_service, N_(\"show service information\")),\n>                 OPT_END()\n>         };\n> +       enum protocol_version version = determine_protocol_version_server();\n>\n>         packet_trace_identity(\"upload-pack\");\n>         read_replace_refs = 0;\n> @@ -50,7 +53,17 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)\n>         if (!enter_repo(dir, strict))\n>                 die(\"'%s' does not appear to be a git repository\", dir);\n>\n> -       switch (determine_protocol_version_server()) {\n> +\n> +       if (show_service) {\n> +               if (!advertise_refs)\n> +                       die(_(\"options '%s' and '%s' should be used together\"), \"--show-service\", \"--http-backend-info-refs\");\n> +               if (version != protocol_v2) {\n> +                       packet_write_fmt(1, \"# service=git-upload-pack\\n\");\n> +                       packet_flush(1);\n> +               }\n> +       }\n> +\n> +       switch (version) {\n>         case protocol_v2:\n>                 if (advertise_refs)\n>                         protocol_v2_advertise_capabilities();\n> diff --git a/http-backend.c b/http-backend.c\n> index 89aad1b42c7..74c2c7bb606 100644\n> --- a/http-backend.c\n> +++ b/http-backend.c\n> @@ -539,6 +539,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)\n>         if (service_name) {\n>                 const char *argv[] = {NULL /* service name */,\n>                         \"--http-backend-info-refs\",\n> +                       \"--show-service\",\n>                         \".\", NULL};\n>                 struct rpc_service *svc = select_service(hdr, service_name);\n>\n> @@ -547,12 +548,6 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)\n>                 hdr_str(hdr, content_type, buf.buf);\n>                 end_headers(hdr);\n>\n> -\n> -               if (determine_protocol_version_server() != protocol_v2) {\n> -                       packet_write_fmt(1, \"# service=git-%s\\n\", svc->name);\n> -                       packet_flush(1);\n> -               }\n> -\n>                 argv[0] = svc->name;\n>                 run_service(argv, 0);\n>\n> diff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh\n> index b1cfe8b7dba..32431266eb9 100755\n> --- a/t/t5555-http-smart-common.sh\n> +++ b/t/t5555-http-smart-common.sh\n> @@ -159,4 +159,124 @@ test_expect_success 'git receive-pack --advertise-refs: v2' '\n>         test_cmp actual expect\n>  '\n>\n> +test_expect_success 'git upload-pack --advertise-refs --show-service: v0' '\n> +       # With no specified protocol\n> +       cat >expect <<-EOF &&\n> +       # service=git-upload-pack\n> +       0000\n> +       $(git rev-parse HEAD) HEAD\n> +       $(git rev-parse HEAD) $(git symbolic-ref HEAD)\n> +       0000\n> +       EOF\n> +\n> +       git upload-pack --advertise-refs --show-service . >out 2>err &&\n> +       test-tool pkt-line unpack <out >actual &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect &&\n> +\n> +       # With explicit v0\n> +       GIT_PROTOCOL=version=0 \\\n> +       git upload-pack --advertise-refs --show-service . >out 2>err &&\n> +       test-tool pkt-line unpack <out >actual 2>err &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect\n> +\n> +'\n> +\n> +test_expect_success 'git receive-pack --advertise-refs --show-service: v0' '\n> +       # With no specified protocol\n> +       cat >expect <<-EOF &&\n> +       # service=git-receive-pack\n> +       0000\n> +       $(git rev-parse HEAD) $(git symbolic-ref HEAD)\n> +       0000\n> +       EOF\n> +\n> +       git receive-pack --advertise-refs --show-service . >out 2>err &&\n> +       test-tool pkt-line unpack <out >actual &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect &&\n> +\n> +       # With explicit v0\n> +       GIT_PROTOCOL=version=0 \\\n> +       git receive-pack --advertise-refs --show-service . >out 2>err &&\n> +       test-tool pkt-line unpack <out >actual 2>err &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect\n> +\n> +'\n> +\n> +test_expect_success 'git upload-pack --advertise-refs --show-service: v1' '\n> +       # With no specified protocol\n> +       cat >expect <<-EOF &&\n> +       # service=git-upload-pack\n> +       0000\n> +       version 1\n> +       $(git rev-parse HEAD) HEAD\n> +       $(git rev-parse HEAD) $(git symbolic-ref HEAD)\n> +       0000\n> +       EOF\n> +\n> +       GIT_PROTOCOL=version=1 \\\n> +       git upload-pack --advertise-refs --show-service . >out &&\n> +\n> +       test-tool pkt-line unpack <out >actual 2>err &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect\n> +'\n> +\n> +test_expect_success 'git receive-pack --advertise-refs --show-service: v1' '\n> +       # With no specified protocol\n> +       cat >expect <<-EOF &&\n> +       # service=git-receive-pack\n> +       0000\n> +       version 1\n> +       $(git rev-parse HEAD) $(git symbolic-ref HEAD)\n> +       0000\n> +       EOF\n> +\n> +       GIT_PROTOCOL=version=1 \\\n> +       git receive-pack --advertise-refs --show-service . >out &&\n> +\n> +       test-tool pkt-line unpack <out >actual 2>err &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect\n> +'\n> +\n> +test_expect_success 'git upload-pack --advertise-refs --show-service: v2' '\n> +       cat >expect <<-EOF &&\n> +       version 2\n> +       agent=FAKE\n> +       ls-refs=unborn\n> +       fetch=shallow wait-for-done\n> +       server-option\n> +       object-format=$(test_oid algo)\n> +       object-info\n> +       0000\n> +       EOF\n> +\n> +       GIT_PROTOCOL=version=2 \\\n> +       GIT_USER_AGENT=FAKE \\\n> +       git upload-pack --advertise-refs --show-service . >out 2>err &&\n> +\n> +       test-tool pkt-line unpack <out >actual &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect\n> +'\n> +\n> +test_expect_success 'git receive-pack --advertise-refs --show-service: v2' '\n> +       # There is no v2 yet for receive-pack, implicit v0\n> +       cat >expect <<-EOF &&\n> +       $(git rev-parse HEAD) $(git symbolic-ref HEAD)\n> +       0000\n> +       EOF\n> +\n> +       GIT_PROTOCOL=version=2 \\\n> +       git receive-pack --advertise-refs --show-service . >out 2>err &&\n> +\n> +       test-tool pkt-line unpack <out >actual &&\n> +       test_must_be_empty err &&\n> +       test_cmp actual expect\n> +'\n> +\n>  test_done\n>\n> base-commit: 7580f92ffa970b9484ac214f7b53cec5e26ca4bc\n> --\n> gitgitgadget\n"}]}