In a previous change, the --negotiation-restrict command-line option of 'git
fetch' was added as a synonym of --negotiation-tip. Both of these options
restrict the set of 'haves' the client can send as part of negotiation.
This was previously not available via a configuration option. Add a new
'remote.<name>.negotiationRestrict' multi-valued config option that updates
'git fetch <name>' to use these restrictions by default.
If the user provides even one --negotiation-restrict argument, then the
config is ignored.
An empty value resets the value list to allow ignoring earlier config
values, such as those that might be set in system or global config.
Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Derrick Stolee committedMay 19, 2026 at 16:24 UTC8bb252f86c30a3066ec64f99f94719c01a53743a
5 files changed+71-7
Documentation/config/remote.adoc
+18
index 91e46f66f5..4dcf81fbce 100644--- a/Documentation/config/remote.adoc+++ b/Documentation/config/remote.adoc@@ -107,6 +107,24 @@ priority configuration file (e.g. `.git/config` in a repository) to clear the values inherited from a lower priority configuration files (e.g. `$HOME/.gitconfig`).+remote.<name>.negotiationRestrict::+ When negotiating with this remote during `git fetch`, 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.
builtin/fetch.c
+21-7
index 2ba0051d52..a957739f37 100644--- a/builtin/fetch.c+++ b/builtin/fetch.c@@ -1601,6 +1601,19 @@ static struct transport *prepare_transport(struct remote *remote, int deepen, else warning(_("ignoring %s because the protocol does not support it"), "--negotiation-restrict");+ } else if (remote->negotiation_restrict.nr) {+ struct string_list_item *item;+ for_each_string_list_item(item, &remote->negotiation_restrict)+ string_list_append(&negotiation_restrict, item->string);+ if (transport->smart_options)+ add_negotiation_restrict_tips(transport->smart_options);+ else {+ struct strbuf config_name = STRBUF_INIT;+ strbuf_addf(&config_name, "remote.%s.negotiationRestrict", remote->name);+ warning(_("ignoring %s because the protocol does not support it"),+ config_name.buf);+ strbuf_release(&config_name);+ } } return transport; }@@ -2658,10 +2671,6 @@ int cmd_fetch(int argc, config.display_format = DISPLAY_FORMAT_PORCELAIN; }- if (negotiate_only && !negotiation_restrict.nr)- die(_("%s needs one or more %s"), "--negotiate-only",- "--negotiation-restrict=*");- if (deepen_relative) { if (deepen_relative < 0) die(_("negative depth in --deepen is not supported"));@@ -2749,14 +2758,19 @@ 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->acked_commits = &acked_commits;- } else {++ 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;+ if (server_options.nr) gtransport->server_options = &server_options; result = transport_fetch_refs(gtransport, NULL);