All of lore.kernel.org
 help / color / mirror / Atom feed
From: Derrick Stolee <stolee@gmail.com>
To: Matthew John Cheetham <mjcheetham@outlook.com>,
	Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>,
	git@vger.kernel.org
Cc: gitster@pobox.com, ps@pks.im
Subject: Re: [PATCH v3 4/7] remote: add remote.*.negotiationRestrict config
Date: Tue, 12 May 2026 10:52:38 -0400	[thread overview]
Message-ID: <b7df2426-912b-44f0-82b1-d246d5558484@gmail.com> (raw)
In-Reply-To: <VI0PR03MB11634BD90B47B89A7631F5DE5C0392@VI0PR03MB11634.eurprd03.prod.outlook.com>

On 5/12/26 8:29 AM, Matthew John Cheetham wrote:
> On 2026-04-22 16:25, Derrick Stolee via GitGitGadget wrote:
> 
>> From: Derrick Stolee<stolee@gmail.com>
>>
>> In a previous change, the --negotiation-restrict command-line option of
>> 'git fetch' was added as a synonym of --negotiation-tips. Both of these
>> options restrict the set of 'haves' the client can send as part of
>> negotiation.
> 
> s/tips/tip/ as per the previous patch comments. Not important either
> way.

Thanks.

>> +remote.<name>.negotiationRestrict::
>> +    When negotiating with this remote during `git fetch` and `git push`,
>> +    restrict the commits advertised as "have" lines to only those
>> +    reachable from refs matching the given patterns.  This multi-valued
>> +    config option behaves like `--negotiation-restrict` on the command
>> +    line.
>> ++
>> +Each value is either an exact ref name (e.g. `refs/heads/release`) or a
>> +glob pattern (e.g. `refs/heads/release/*`).  The pattern syntax is the
>> +same as for `--negotiation-restrict`.
>> ++
>> +These config values are used as defaults for the `--negotiation-restrict`
>> +command-line option.  If `--negotiation-restrict` (or its synonym
>> +`--negotiation-tip`) is specified on the command line, then the config
>> +values are not used.
>> ++
>> +Blank values signal to ignore all previous values, allowing a reset of
>> +the list from broader config scenarios.
>> +
>>   remote.<name>.followRemoteHEAD::
>>       How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`
>>       when fetching using the configured refspecs of a remote.
> 
> 
> You say "during `git fetch` and `git push`", but does `push` actually
> honour the new config?
> 
> When the `push.negotiate` config is on then
> `get_commons_through_negotiation()` from send-pack.c shells out to
> `git fetch --negotiate-only` with one `--negotiation-tip=<oid>` arg per
> ref being pushed, then the URL. This means the CLI restrict list is
> always non-empty in the subprocess so in `prepare_transport()` (in the
> below hunk) the `if (negotiation_restrict.nr)` arm is always taken and the new 
> `else if (remote->negotiation_restrict.nr)` arm is never taken.
> 
> BUT.. reading ahead I see that patch 7 actually wires up negotiation
> config for push - so my commentary here will be moot! Do we want to drop
> the "and `git push`" part from this until patch 7, when it is wired up
> appropriately?

You're right that this documentation is premature about 'git push'.

> One other suggestion: perhaps we should clarify that `push.negotiate`
> needs to be set for `remote.<name>.negotiationRestrict` to be honoured
> during pushes?

Yes. I'll rewrite this to focus on 'git fetch'. Then in patch 7 I can
add a new detail about how to make this behavior be respected in 'git push'.

>>       if (deepen_relative) {
>>           if (deepen_relative < 0)
>>               die(_("negative depth in --deepen is not supported"));
>> @@ -2749,6 +2758,10 @@ int cmd_fetch(int argc,
>>           if (!remote)
>>               die(_("must supply remote when using --negotiate-only"));
>>           gtransport = prepare_transport(remote, 1, &filter_options);
>> +        if (!gtransport->smart_options ||
>> +            !gtransport->smart_options->negotiation_restrict_tips)
>> +            die(_("%s needs one or more %s"), "--negotiate-only",
>> +                "--negotiation-restrict=*");
>>           if (gtransport->smart_options) {
>>               gtransport->smart_options->acked_commits = &acked_commits;
>>           } else {
> 
> 
> This new condition fires whenever `gtransport->smart_options` is NULL,
> i.e. the transport doesn't support smart options. Before this case was
> handled three lines after this hunk by:
> 
>    } else {
>        warning(_("protocol does not support --negotiate-only, exiting"));
>        result = 1;
>        trace2_region_leave("fetch", "negotiate-only", the_repository);
>        goto cleanup;
>    }
> 
> What happens now if a user runs --negotiate-only against a non-smart
> transport is they see an odd message:
> 
>    fatal: --negotiate-only needs one or more --negotiation-restrict=*
> 
> ..but they may have specified --negotiation-restrict options.
> 
> Do we instead want &&?
> 
>       if (gtransport->smart_options &&
>           !gtransport->smart_options->negotiation_restrict_tips)
>           die(_("%s needs one or more %s"), "--negotiate-only",
>               "--negotiation-restrict=*");
You are right that we want to say "we have smart options but haven't
specified restrict arguments" so we can leave the later if/else to
handle the null smart_options case. But actually, I think that it
would be better to reorganize the conditions altogether:

	if (!gtransport->smart_options) {
		warning(_("protocol does not support --negotiate-only, "exiting"));
		result = 1;
		trace2_region_leave("fetch", "negotiate-only", the_repository);
		goto cleanup;
	}
	if (!gtransport->smart_options->negotiation_restrict_tips)
		die(_("%s needs one or more %s"), "--negotiate-only",
		    "--negotiation-restrict=*");

	gtransport->smart_options->acked_commits = &acked_commits;

This is easier to reason about:

* If we don't have smart options, then skip out of the negotiation logic.
* If we don't have restrict tips, then die().
* Do the negotiation logic only if the previous two conditions didn't hold.

>> @@ -562,6 +564,12 @@ static int handle_config(const char *key, const char *value,
>>       } else if (!strcmp(subkey, "serveroption")) {
>>           return parse_transport_option(key, value,
>>                             &remote->server_options);
>> +    } else if (!strcmp(subkey, "negotiationrestrict")) {
>> +        /* reset list on empty value. */
>> +        if (!value || !*value)
>> +            string_list_clear(&remote->negotiation_restrict, 0);
>> +        else
>> +            string_list_append(&remote->negotiation_restrict, value);
>>       } else if (!strcmp(subkey, "followremotehead")) {
>>           const char *no_warn_branch;
>>           if (!strcmp(value, "never"))
> 
> 
> Here we use the 'empty value means reset the list' pattern, but I notice
> that the `parse_transport_option()` function already supports this reset
> pattern (and used by serveroption above), with a small difference:
> 
>    if (!value)
>        return config_error_nonbool(var);
>    if (!*value)
>        string_list_clear(transport_options, 0);
> 
> So NULL is an error, but empty string is 'reset'. Is it worth being
> consistent with other options that use `parse_transport_options`?

Thanks for catching this! Let's be consistent. NULL is likely
impossible in this case, but let's be consistent. It also needs
to return.

Thanks,
-Stolee


  reply	other threads:[~2026-05-12 14:52 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-08 14:36 [PATCH 0/4] fetch: add --must-have and remote.*.mustHave Derrick Stolee via GitGitGadget
2026-04-08 14:36 ` [PATCH 1/4] t5516: fix test order flakiness Derrick Stolee via GitGitGadget
2026-04-08 14:36 ` [PATCH 2/4] fetch: add --must-have option for negotiation Derrick Stolee via GitGitGadget
2026-04-08 14:36 ` [PATCH 3/4] remote: add mustHave config as default for --must-have Derrick Stolee via GitGitGadget
2026-04-08 14:36 ` [PATCH 4/4] send-pack: pass --must-have for push negotiation Derrick Stolee via GitGitGadget
2026-04-08 18:59 ` [PATCH 0/4] fetch: add --must-have and remote.*.mustHave Junio C Hamano
2026-04-09 12:53   ` Derrick Stolee
2026-04-15 15:14 ` [PATCH v2 0/7] fetch: rework negotiation tip options Derrick Stolee via GitGitGadget
2026-04-15 15:14   ` [PATCH v2 1/7] t5516: fix test order flakiness Derrick Stolee via GitGitGadget
2026-04-15 15:14   ` [PATCH v2 2/7] fetch: add --negotiation-restrict option Derrick Stolee via GitGitGadget
2026-04-15 21:57     ` Junio C Hamano
2026-04-19 23:00       ` Derrick Stolee
2026-04-20 10:32         ` Junio C Hamano
2026-04-20 11:35           ` Derrick Stolee
2026-04-15 15:14   ` [PATCH v2 3/7] transport: rename negotiation_tips Derrick Stolee via GitGitGadget
2026-04-20  8:11     ` Patrick Steinhardt
2026-04-15 15:14   ` [PATCH v2 4/7] remote: add remote.*.negotiationRestrict config Derrick Stolee via GitGitGadget
2026-04-15 19:16     ` Junio C Hamano
2026-04-15 15:14   ` [PATCH v2 5/7] fetch: add --negotiation-require option for negotiation Derrick Stolee via GitGitGadget
2026-04-15 19:50     ` Junio C Hamano
2026-04-21 18:06       ` Derrick Stolee
2026-04-20  8:11     ` Patrick Steinhardt
2026-04-20 11:41       ` Derrick Stolee
2026-04-15 15:14   ` [PATCH v2 6/7] remote: add negotiationRequire config as default for --negotiation-require Derrick Stolee via GitGitGadget
2026-04-15 15:14   ` [PATCH v2 7/7] send-pack: pass negotiation config in push Derrick Stolee via GitGitGadget
2026-04-22 15:25   ` [PATCH v3 0/7] fetch: rework negotiation tip options Derrick Stolee via GitGitGadget
2026-04-22 15:25     ` [PATCH v3 1/7] t5516: fix test order flakiness Derrick Stolee via GitGitGadget
2026-05-12 10:50       ` Matthew John Cheetham
2026-04-22 15:25     ` [PATCH v3 2/7] fetch: add --negotiation-restrict option Derrick Stolee via GitGitGadget
2026-05-12 11:11       ` Matthew John Cheetham
2026-05-12 14:23         ` Derrick Stolee
2026-04-22 15:25     ` [PATCH v3 3/7] transport: rename negotiation_tips Derrick Stolee via GitGitGadget
2026-05-12 11:30       ` Matthew John Cheetham
2026-05-12 14:33         ` Derrick Stolee
2026-04-22 15:25     ` [PATCH v3 4/7] remote: add remote.*.negotiationRestrict config Derrick Stolee via GitGitGadget
2026-05-12 12:29       ` Matthew John Cheetham
2026-05-12 14:52         ` Derrick Stolee [this message]
2026-04-22 15:25     ` [PATCH v3 5/7] fetch: add --negotiation-include option for negotiation Derrick Stolee via GitGitGadget
2026-05-12 14:38       ` Matthew John Cheetham
2026-05-12 16:54         ` Derrick Stolee
2026-04-22 15:25     ` [PATCH v3 6/7] remote: add remote.*.negotiationInclude config Derrick Stolee via GitGitGadget
2026-05-12 14:54       ` Matthew John Cheetham
2026-05-12 17:55         ` Derrick Stolee
2026-04-22 15:25     ` [PATCH v3 7/7] send-pack: pass negotiation config in push Derrick Stolee via GitGitGadget
2026-05-12 15:14       ` Matthew John Cheetham
2026-05-14 12:41     ` [PATCH v4 0/8] fetch: rework negotiation tip options Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 1/8] t5516: fix test order flakiness Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 2/8] fetch: add --negotiation-restrict option Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 3/8] transport: rename negotiation_tips Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 4/8] remote: add remote.*.negotiationRestrict config Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 5/8] negotiator: add have_sent() interface Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 6/8] fetch: add --negotiation-include option for negotiation Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 7/8] remote: add remote.*.negotiationInclude config Derrick Stolee via GitGitGadget
2026-05-14 12:41       ` [PATCH v4 8/8] send-pack: pass negotiation config in push Derrick Stolee via GitGitGadget

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b7df2426-912b-44f0-82b1-d246d5558484@gmail.com \
    --to=stolee@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=gitster@pobox.com \
    --cc=mjcheetham@outlook.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.