{"thread":{"id":"56030","subject":"[PATCH 0/3] fetch: fix segfault, missing docs in --negotiate-only","startedAt":"2021-06-30T16:38:18Z","lastAt":"2021-07-08T10:53:25Z","messageCount":9,"participants":["Ævar Arnfjörð Bjarmason","Jonathan Tan"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"428828","messageId":"cover-0.3-00000000000-20210630T163329Z-avarab@gmail.com","threadId":"56030","inReplyTo":null,"subject":"[PATCH 0/3] fetch: fix segfault, missing docs in --negotiate-only","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-30T16:38:09Z","receivedAt":"2021-06-30T16:38:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The recently added --negotiate-only option segfaults when not combined\nwith --negotiation-tip=*, this fixes that, and adds documentation for\nit.\n\n1/3 is a related fix to save us some work in a codepath checking the\n\"--negotiate-only\" and other passed-in options in send-pack.c.\n\nÆvar Arnfjörð Bjarmason (3):\n  send-pack.c: move \"no refs in common\" abort earlier\n  fetch: document the --negotiate-only option\n  fetch: fix segfault in --negotiate-only without --negotiation-tip=*\n\n Documentation/config/fetch.txt  |  3 ++-\n Documentation/fetch-options.txt | 13 +++++++++++--\n builtin/fetch.c                 |  3 +++\n send-pack.c                     | 11 ++++++-----\n t/t5702-protocol-v2.sh          | 17 +++++++++++++++++\n 5 files changed, 39 insertions(+), 8 deletions(-)\n\n-- \n2.32.0.619.g53a98c35da0\n\n"},{"id":"428829","messageId":"patch-1.3-1cd8b98d3d6-20210630T163329Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210630T163329Z-avarab@gmail.com","subject":"[PATCH 1/3] send-pack.c: move \"no refs in common\" abort earlier","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-30T16:38:10Z","receivedAt":"2021-06-30T16:38:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the early return if we have no remote refs in send_pack()\nearlier.\n\nWhen this was added in 4c353e890c0 (Warn when send-pack does nothing,\n2005-12-04) one of the first things we'd do was to abort, but as of\ncfee10a773b (send-pack/receive-pack: allow errors to be reported back\nto pusher., 2005-12-25) we've added numerous server_supports()\nconditions that are acted on later in the function, that won't be used\nif we don't have remote refs.\n\nThen as of 477673d6f39 (send-pack: support push negotiation,\n2021-05-04) we started doing even more work on the assumption that we\nhad some remote refs to feed to --negotiation-tip=* options.\n\nWe only hit this condition if we have nothing to push, so we don't\nneed to consider \"push.negotiate\" etc. only to do nothing with that\ninformation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n send-pack.c | 11 ++++++-----\n 1 file changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/send-pack.c b/send-pack.c\nindex 9cb9f716509..5a79e0e7110 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -486,6 +486,12 @@ int send_pack(struct send_pack_args *args,\n \tconst char *push_cert_nonce = NULL;\n \tstruct packet_reader reader;\n \n+\tif (!remote_refs) {\n+\t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\"\n+\t\t\t\"Perhaps you should specify a branch.\\n\");\n+\t\treturn 0;\n+\t}\n+\n \tgit_config_get_bool(\"push.negotiate\", &push_negotiate);\n \tif (push_negotiate)\n \t\tget_commons_through_negotiation(args->url, remote_refs, &commons);\n@@ -534,11 +540,6 @@ int send_pack(struct send_pack_args *args,\n \t\t}\n \t}\n \n-\tif (!remote_refs) {\n-\t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\"\n-\t\t\t\"Perhaps you should specify a branch.\\n\");\n-\t\treturn 0;\n-\t}\n \tif (args->atomic && !atomic_supported)\n \t\tdie(_(\"the receiving end does not support --atomic push\"));\n \n-- \n2.32.0.619.g53a98c35da0\n\n"},{"id":"428830","messageId":"patch-3.3-38930024d95-20210630T163329Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210630T163329Z-avarab@gmail.com","subject":"[PATCH 3/3] fetch: fix segfault in --negotiate-only without --negotiation-tip=*","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-30T16:38:12Z","receivedAt":"2021-06-30T16:38:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The recent --negotiate-only option would segfault in the call to\noid_array_for_each() in negotiate_using_fetch() unless one or more\n--negotiation-tip=* options were provided.\n\nAll of the other tests for the feature combine both, but nothing was\nchecking this assumption, let's do that and add a test for it. Fixes a\nbug in 9c1e657a8fd (fetch: teach independent negotiation (no\npackfile), 2021-05-04).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/fetch.c        |  3 +++\n t/t5702-protocol-v2.sh | 17 +++++++++++++++++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 9191620e50c..25740c13df1 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1990,6 +1990,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t\tfetch_config_from_gitmodules(sfjc, rs);\n \t}\n \n+\tif (negotiate_only && !negotiation_tip.nr)\n+\t\tdie(_(\"--negotiate-only needs one or more --negotiate-tip=*\"));\n+\n \tif (deepen_relative) {\n \t\tif (deepen_relative < 0)\n \t\t\tdie(_(\"Negative depth in --deepen is not supported\"));\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex 66af411057c..920815478c7 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -599,6 +599,23 @@ setup_negotiate_only () {\n \ttest_commit -C client three\n }\n \n+test_expect_success 'usage: --negotiate-only without --negotiation-tip' '\n+\tSERVER=\"server\" &&\n+\tURI=\"file://$(pwd)/server\" &&\n+\n+\tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n+\n+\tcat >err.expect <<-\\EOF &&\n+\tfatal: --negotiate-only needs one or more --negotiate-tip=*\n+\tEOF\n+\n+\ttest_must_fail git -c protocol.version=2 -C client fetch \\\n+\t\t--negotiate-only \\\n+\t\torigin 2>err.actual &&\n+\tcat err &&\n+\ttest_cmp err.expect err.actual\n+'\n+\n test_expect_success 'file:// --negotiate-only' '\n \tSERVER=\"server\" &&\n \tURI=\"file://$(pwd)/server\" &&\n-- \n2.32.0.619.g53a98c35da0\n\n"},{"id":"428831","messageId":"patch-2.3-7ff734ed70a-20210630T163329Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210630T163329Z-avarab@gmail.com","subject":"[PATCH 2/3] fetch: document the --negotiate-only option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-30T16:38:11Z","receivedAt":"2021-06-30T16:38:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"There was no documentation for the --negotiate-only option added in\n9c1e657a8fd (fetch: teach independent negotiation (no packfile),\n2021-05-04), only documentation for the related push.negotiation\noption added in the following commit in 477673d6f39 (send-pack:\nsupport push negotiation, 2021-05-04).\n\nLet's document it, and update the cross-linking I'd added between\n--negotiation-tip=* and 'fetch.negotiationAlgorithm' in\n526608284a7 (fetch doc: cross-link two new negotiation options,\n2018-08-01).\n\nI think it would be better to say \"in common with the remote\" here\nthan \"...the server\", but the documentation for --negotiation-tip=*\nabove this talks about \"the server\", so let's continue doing that in\nthis related option. See 3390e42adb3 (fetch-pack: support negotiation\ntip whitelist, 2018-07-02) for that documentation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/fetch.txt  |  3 ++-\n Documentation/fetch-options.txt | 13 +++++++++++--\n 2 files changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt\nindex 6af6f5edb27..63748c02b72 100644\n--- a/Documentation/config/fetch.txt\n+++ b/Documentation/config/fetch.txt\n@@ -69,7 +69,8 @@ fetch.negotiationAlgorithm::\n \tsetting defaults to \"skipping\".\n \tUnknown values will cause 'git fetch' to error out.\n +\n-See also the `--negotiation-tip` option for linkgit:git-fetch[1].\n+See also the `--negotiate-only` and `--negotiation-tip` options to\n+linkgit:git-fetch[1].\n \n fetch.showForcedUpdates::\n \tSet to false to enable `--no-show-forced-updates` in\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 9e7b4e189ce..e967ff1874c 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -62,8 +62,17 @@ The argument to this option may be a glob on ref names, a ref, or the (possibly\n abbreviated) SHA-1 of a commit. Specifying a glob is equivalent to specifying\n this option multiple times, one for each matching ref name.\n +\n-See also the `fetch.negotiationAlgorithm` configuration variable\n-documented in linkgit:git-config[1].\n+See also the `fetch.negotiationAlgorithm` and `push.negotiate`\n+configuration variables documented in linkgit:git-config[1], and the\n+`--negotiate-only` option below.\n+\n+--negotiate-only::\n+\tDo not fetch anything from the server, and instead print the\n+\tancestors of the provided `--negotiation-tip=*` arguments,\n+\twhich we have in common with the server.\n++\n+Internally this is used to implement the `push.negotiate` option, see\n+linkgit:git-config[1].\n \n --dry-run::\n \tShow what would be done, without making any changes.\n-- \n2.32.0.619.g53a98c35da0\n\n"},{"id":"428846","messageId":"20210630180157.1227166-1-jonathantanmy@google.com","threadId":"56030","inReplyTo":"patch-3.3-38930024d95-20210630T163329Z-avarab@gmail.com","subject":"Re: [PATCH 3/3] fetch: fix segfault in --negotiate-only without --negotiation-tip=*","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2021-06-30T18:01:57Z","receivedAt":"2021-06-30T18:02:05Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"> diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\n> index 66af411057c..920815478c7 100755\n> --- a/t/t5702-protocol-v2.sh\n> +++ b/t/t5702-protocol-v2.sh\n> @@ -599,6 +599,23 @@ setup_negotiate_only () {\n>  \ttest_commit -C client three\n>  }\n>  \n> +test_expect_success 'usage: --negotiate-only without --negotiation-tip' '\n> +\tSERVER=\"server\" &&\n> +\tURI=\"file://$(pwd)/server\" &&\n> +\n> +\tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n> +\n> +\tcat >err.expect <<-\\EOF &&\n> +\tfatal: --negotiate-only needs one or more --negotiate-tip=*\n> +\tEOF\n> +\n> +\ttest_must_fail git -c protocol.version=2 -C client fetch \\\n> +\t\t--negotiate-only \\\n> +\t\torigin 2>err.actual &&\n> +\tcat err &&\n\nI think I inadvertently left a similar line in other tests in this file, but\nthis shouldn't be in.\n\nOther than that, all the patches look good to me. Thanks for taking a look at this.\n\nI have a patch set [1] that fixes related bugs (but not this one - in\nparticular, --negotiate-only without --negotiation-tip still fails, so we still\nneed this patch set). I've tried merging my set into this set; the merge is\nclean and all tests still pass, so there shouldn't be any problems with that.\n\n[1] https://lore.kernel.org/git/cover.1624486920.git.jonathantanmy@google.com/\n"},{"id":"429483","messageId":"cover-0.3-00000000000-20210708T105034Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210630T163329Z-avarab@gmail.com","subject":"[PATCH v2 0/3] fetch: fix segfault, missing docs in --negotiate-only","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-07-08T10:53:12Z","receivedAt":"2021-07-08T10:53:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a segfault in recent code, per v1's:\nhttps://lore.kernel.org/git/cover-0.3-00000000000-20210630T163329Z-avarab@gmail.com/\n\nFixes a stray \"cat err\" that snuck out of the lab and into the test,\nspotted by Jonathan Tan.\n\nJunio: You picked this up as ab/fetch-negotiate-segv-fix and it's\nmarked as \"Will merge to 'next'\", but it's not there yet. Hopefully\nyou'll see this before it's merged down. Sorry about the delay.\n\nÆvar Arnfjörð Bjarmason (3):\n  send-pack.c: move \"no refs in common\" abort earlier\n  fetch: document the --negotiate-only option\n  fetch: fix segfault in --negotiate-only without --negotiation-tip=*\n\n Documentation/config/fetch.txt  |  3 ++-\n Documentation/fetch-options.txt | 13 +++++++++++--\n builtin/fetch.c                 |  3 +++\n send-pack.c                     | 11 ++++++-----\n t/t5702-protocol-v2.sh          | 16 ++++++++++++++++\n 5 files changed, 38 insertions(+), 8 deletions(-)\n\nRange-diff against v1:\n1:  1cd8b98d3d6 = 1:  10375a6484e send-pack.c: move \"no refs in common\" abort earlier\n2:  7ff734ed70a = 2:  f86f4fc0e6f fetch: document the --negotiate-only option\n3:  38930024d95 ! 3:  491d72c35a0 fetch: fix segfault in --negotiate-only without --negotiation-tip=*\n    @@ t/t5702-protocol-v2.sh: setup_negotiate_only () {\n     +\ttest_must_fail git -c protocol.version=2 -C client fetch \\\n     +\t\t--negotiate-only \\\n     +\t\torigin 2>err.actual &&\n    -+\tcat err &&\n     +\ttest_cmp err.expect err.actual\n     +'\n     +\n-- \n2.32.0.636.g43e71d69cff\n\n"},{"id":"429484","messageId":"patch-1.3-10375a6484e-20210708T105034Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210708T105034Z-avarab@gmail.com","subject":"[PATCH v2 1/3] send-pack.c: move \"no refs in common\" abort earlier","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-07-08T10:53:13Z","receivedAt":"2021-07-08T10:53:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the early return if we have no remote refs in send_pack()\nearlier.\n\nWhen this was added in 4c353e890c0 (Warn when send-pack does nothing,\n2005-12-04) one of the first things we'd do was to abort, but as of\ncfee10a773b (send-pack/receive-pack: allow errors to be reported back\nto pusher., 2005-12-25) we've added numerous server_supports()\nconditions that are acted on later in the function, that won't be used\nif we don't have remote refs.\n\nThen as of 477673d6f39 (send-pack: support push negotiation,\n2021-05-04) we started doing even more work on the assumption that we\nhad some remote refs to feed to --negotiation-tip=* options.\n\nWe only hit this condition if we have nothing to push, so we don't\nneed to consider \"push.negotiate\" etc. only to do nothing with that\ninformation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n send-pack.c | 11 ++++++-----\n 1 file changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/send-pack.c b/send-pack.c\nindex 9cb9f716509..5a79e0e7110 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -486,6 +486,12 @@ int send_pack(struct send_pack_args *args,\n \tconst char *push_cert_nonce = NULL;\n \tstruct packet_reader reader;\n \n+\tif (!remote_refs) {\n+\t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\"\n+\t\t\t\"Perhaps you should specify a branch.\\n\");\n+\t\treturn 0;\n+\t}\n+\n \tgit_config_get_bool(\"push.negotiate\", &push_negotiate);\n \tif (push_negotiate)\n \t\tget_commons_through_negotiation(args->url, remote_refs, &commons);\n@@ -534,11 +540,6 @@ int send_pack(struct send_pack_args *args,\n \t\t}\n \t}\n \n-\tif (!remote_refs) {\n-\t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\"\n-\t\t\t\"Perhaps you should specify a branch.\\n\");\n-\t\treturn 0;\n-\t}\n \tif (args->atomic && !atomic_supported)\n \t\tdie(_(\"the receiving end does not support --atomic push\"));\n \n-- \n2.32.0.636.g43e71d69cff\n\n"},{"id":"429485","messageId":"patch-2.3-f86f4fc0e6f-20210708T105034Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210708T105034Z-avarab@gmail.com","subject":"[PATCH v2 2/3] fetch: document the --negotiate-only option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-07-08T10:53:14Z","receivedAt":"2021-07-08T10:53:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"There was no documentation for the --negotiate-only option added in\n9c1e657a8fd (fetch: teach independent negotiation (no packfile),\n2021-05-04), only documentation for the related push.negotiation\noption added in the following commit in 477673d6f39 (send-pack:\nsupport push negotiation, 2021-05-04).\n\nLet's document it, and update the cross-linking I'd added between\n--negotiation-tip=* and 'fetch.negotiationAlgorithm' in\n526608284a7 (fetch doc: cross-link two new negotiation options,\n2018-08-01).\n\nI think it would be better to say \"in common with the remote\" here\nthan \"...the server\", but the documentation for --negotiation-tip=*\nabove this talks about \"the server\", so let's continue doing that in\nthis related option. See 3390e42adb3 (fetch-pack: support negotiation\ntip whitelist, 2018-07-02) for that documentation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/fetch.txt  |  3 ++-\n Documentation/fetch-options.txt | 13 +++++++++++--\n 2 files changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt\nindex 6af6f5edb27..63748c02b72 100644\n--- a/Documentation/config/fetch.txt\n+++ b/Documentation/config/fetch.txt\n@@ -69,7 +69,8 @@ fetch.negotiationAlgorithm::\n \tsetting defaults to \"skipping\".\n \tUnknown values will cause 'git fetch' to error out.\n +\n-See also the `--negotiation-tip` option for linkgit:git-fetch[1].\n+See also the `--negotiate-only` and `--negotiation-tip` options to\n+linkgit:git-fetch[1].\n \n fetch.showForcedUpdates::\n \tSet to false to enable `--no-show-forced-updates` in\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 9e7b4e189ce..e967ff1874c 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -62,8 +62,17 @@ The argument to this option may be a glob on ref names, a ref, or the (possibly\n abbreviated) SHA-1 of a commit. Specifying a glob is equivalent to specifying\n this option multiple times, one for each matching ref name.\n +\n-See also the `fetch.negotiationAlgorithm` configuration variable\n-documented in linkgit:git-config[1].\n+See also the `fetch.negotiationAlgorithm` and `push.negotiate`\n+configuration variables documented in linkgit:git-config[1], and the\n+`--negotiate-only` option below.\n+\n+--negotiate-only::\n+\tDo not fetch anything from the server, and instead print the\n+\tancestors of the provided `--negotiation-tip=*` arguments,\n+\twhich we have in common with the server.\n++\n+Internally this is used to implement the `push.negotiate` option, see\n+linkgit:git-config[1].\n \n --dry-run::\n \tShow what would be done, without making any changes.\n-- \n2.32.0.636.g43e71d69cff\n\n"},{"id":"429486","messageId":"patch-3.3-491d72c35a0-20210708T105034Z-avarab@gmail.com","threadId":"56030","inReplyTo":"cover-0.3-00000000000-20210708T105034Z-avarab@gmail.com","subject":"[PATCH v2 3/3] fetch: fix segfault in --negotiate-only without --negotiation-tip=*","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-07-08T10:53:15Z","receivedAt":"2021-07-08T10:53:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The recent --negotiate-only option would segfault in the call to\noid_array_for_each() in negotiate_using_fetch() unless one or more\n--negotiation-tip=* options were provided.\n\nAll of the other tests for the feature combine both, but nothing was\nchecking this assumption, let's do that and add a test for it. Fixes a\nbug in 9c1e657a8fd (fetch: teach independent negotiation (no\npackfile), 2021-05-04).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/fetch.c        |  3 +++\n t/t5702-protocol-v2.sh | 16 ++++++++++++++++\n 2 files changed, 19 insertions(+)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 9191620e50c..25740c13df1 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1990,6 +1990,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t\tfetch_config_from_gitmodules(sfjc, rs);\n \t}\n \n+\tif (negotiate_only && !negotiation_tip.nr)\n+\t\tdie(_(\"--negotiate-only needs one or more --negotiate-tip=*\"));\n+\n \tif (deepen_relative) {\n \t\tif (deepen_relative < 0)\n \t\t\tdie(_(\"Negative depth in --deepen is not supported\"));\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex 66af411057c..78de1ff2ad5 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -599,6 +599,22 @@ setup_negotiate_only () {\n \ttest_commit -C client three\n }\n \n+test_expect_success 'usage: --negotiate-only without --negotiation-tip' '\n+\tSERVER=\"server\" &&\n+\tURI=\"file://$(pwd)/server\" &&\n+\n+\tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n+\n+\tcat >err.expect <<-\\EOF &&\n+\tfatal: --negotiate-only needs one or more --negotiate-tip=*\n+\tEOF\n+\n+\ttest_must_fail git -c protocol.version=2 -C client fetch \\\n+\t\t--negotiate-only \\\n+\t\torigin 2>err.actual &&\n+\ttest_cmp err.expect err.actual\n+'\n+\n test_expect_success 'file:// --negotiate-only' '\n \tSERVER=\"server\" &&\n \tURI=\"file://$(pwd)/server\" &&\n-- \n2.32.0.636.g43e71d69cff\n\n"}]}