Skip to content

Commit 9731f94

Browse files
committed
Merge branch 'ds/fetch-negotiation-options' into jch
The negotiation tip options in "git fetch" have been reworked to allow requiring certain refs to be sent as "have" lines, and to restrict negotiation to a specific set of refs. * ds/fetch-negotiation-options: send-pack: pass negotiation config in push remote: add negotiationRequire config as default for --negotiation-require fetch: add --negotiation-require option for negotiation remote: add remote.*.negotiationRestrict config transport: rename negotiation_tips fetch: add --negotiation-restrict option t5516: fix test order flakiness
2 parents a45c461 + 9f67318 commit 9731f94

File tree

16 files changed

+489
-44
lines changed

16 files changed

+489
-44
lines changed

Documentation/config/remote.adoc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,46 @@ priority configuration file (e.g. `.git/config` in a repository) to clear
107107
the values inherited from a lower priority configuration files (e.g.
108108
`$HOME/.gitconfig`).
109109

110+
remote.<name>.negotiationRestrict::
111+
When negotiating with this remote during `git fetch` and `git push`,
112+
restrict the commits advertised as "have" lines to only those
113+
reachable from refs matching the given patterns. This multi-valued
114+
config option behaves like `--negotiation-restrict` on the command
115+
line.
116+
+
117+
Each value is either an exact ref name (e.g. `refs/heads/release`) or a
118+
glob pattern (e.g. `refs/heads/release/*`). The pattern syntax is the
119+
same as for `--negotiation-restrict`.
120+
+
121+
These config values are used as defaults for the `--negotiation-restrict`
122+
command-line option. If `--negotiation-restrict` (or its synonym
123+
`--negotiation-tip`) is specified on the command line, then the config
124+
values are not used.
125+
126+
remote.<name>.negotiationRequire::
127+
When negotiating with this remote during `git fetch` and `git push`,
128+
the client advertises a list of commits that exist locally. In
129+
repos with many references, this list of "haves" can be truncated.
130+
Depending on data shape, dropping certain references may be
131+
expensive. This multi-valued config option specifies ref patterns
132+
whose tips should always be sent as "have" commits during fetch
133+
negotiation with this remote.
134+
+
135+
Each value is either an exact ref name (e.g. `refs/heads/release`) or a
136+
glob pattern (e.g. `refs/heads/release/*`). The pattern syntax is the same
137+
as for `--negotiation-restrict`.
138+
+
139+
These config values are used as defaults for the `--negotiation-require`
140+
command-line option. If `--negotiation-require` is specified on the
141+
command line, then the config values are not used.
142+
+
143+
This option is additive with the normal negotiation process: the
144+
negotiation algorithm still runs and advertises its own selected commits,
145+
but the refs matching `remote.<name>.negotiationRequire` are sent
146+
unconditionally on top of those heuristically selected commits. This
147+
option is also used during push negotiation when `push.negotiate` is
148+
enabled.
149+
110150
remote.<name>.followRemoteHEAD::
111151
How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`
112152
when fetching using the configured refspecs of a remote.

Documentation/fetch-options.adoc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ the current repository has the same history as the source repository.
4949
`.git/shallow`. This option updates `.git/shallow` and accepts such
5050
refs.
5151

52+
`--negotiation-restrict=(<commit>|<glob>)`::
5253
`--negotiation-tip=(<commit>|<glob>)`::
5354
By default, Git will report, to the server, commits reachable
5455
from all local refs to find common commits in an attempt to
@@ -58,6 +59,9 @@ the current repository has the same history as the source repository.
5859
local ref is likely to have commits in common with the
5960
upstream ref being fetched.
6061
+
62+
`--negotiation-restrict` is the preferred name for this option;
63+
`--negotiation-tip` is accepted as a synonym.
64+
+
6165
This option may be specified more than once; if so, Git will report
6266
commits reachable from any of the given commits.
6367
+
@@ -69,6 +73,29 @@ See also the `fetch.negotiationAlgorithm` and `push.negotiate`
6973
configuration variables documented in linkgit:git-config[1], and the
7074
`--negotiate-only` option below.
7175

76+
`--negotiation-require=<revision>`::
77+
Ensure that the given ref tip is always sent as a "have" line
78+
during fetch negotiation, regardless of what the negotiation
79+
algorithm selects. This is useful to guarantee that common
80+
history reachable from specific refs is always considered, even
81+
when `--negotiation-restrict` restricts the set of tips or when
82+
the negotiation algorithm would otherwise skip them.
83+
+
84+
This option may be specified more than once; if so, each ref is sent
85+
unconditionally.
86+
+
87+
The argument may be an exact ref name (e.g. `refs/heads/release`) or a
88+
glob pattern (e.g. `refs/heads/release/{asterisk}`). The pattern syntax
89+
is the same as for `--negotiation-restrict`.
90+
+
91+
If `--negotiation-restrict` is used, the have set is first restricted by
92+
that option and then increased to include the tips specified by
93+
`--negotiation-require`.
94+
+
95+
If this option is not specified on the command line, then any
96+
`remote.<name>.negotiationRequire` config values for the current remote
97+
are used instead.
98+
7299
`--negotiate-only`::
73100
Do not fetch anything from the server, and instead print the
74101
ancestors of the provided `--negotiation-tip=` arguments,

builtin/fetch.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static struct transport *gsecondary;
9999
static struct refspec refmap = REFSPEC_INIT_FETCH;
100100
static struct string_list server_options = STRING_LIST_INIT_DUP;
101101
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
102+
static struct string_list negotiation_require = STRING_LIST_INIT_NODUP;
102103

103104
struct fetch_config {
104105
enum display_format display_format;
@@ -1534,7 +1535,7 @@ static int add_oid(const struct reference *ref, void *cb_data)
15341535
return 0;
15351536
}
15361537

1537-
static void add_negotiation_tips(struct git_transport_options *smart_options)
1538+
static void add_negotiation_restrict_tips(struct git_transport_options *smart_options)
15381539
{
15391540
struct oid_array *oids = xcalloc(1, sizeof(*oids));
15401541
int i;
@@ -1558,10 +1559,10 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
15581559
refs_for_each_ref_ext(get_main_ref_store(the_repository),
15591560
add_oid, oids, &opts);
15601561
if (old_nr == oids->nr)
1561-
warning("ignoring --negotiation-tip=%s because it does not match any refs",
1562-
s);
1562+
warning(_("ignoring %s=%s because it does not match any refs"),
1563+
"--negotiation-restrict", s);
15631564
}
1564-
smart_options->negotiation_tips = oids;
1565+
smart_options->negotiation_restrict_tips = oids;
15651566
}
15661567

15671568
static struct transport *prepare_transport(struct remote *remote, int deepen,
@@ -1597,9 +1598,40 @@ static struct transport *prepare_transport(struct remote *remote, int deepen,
15971598
}
15981599
if (negotiation_tip.nr) {
15991600
if (transport->smart_options)
1600-
add_negotiation_tips(transport->smart_options);
1601+
add_negotiation_restrict_tips(transport->smart_options);
16011602
else
1602-
warning("ignoring --negotiation-tip because the protocol does not support it");
1603+
warning(_("ignoring %s because the protocol does not support it"),
1604+
"--negotiation-restrict");
1605+
} else if (remote->negotiation_restrict.nr) {
1606+
struct string_list_item *item;
1607+
for_each_string_list_item(item, &remote->negotiation_restrict)
1608+
string_list_append(&negotiation_tip, item->string);
1609+
if (transport->smart_options)
1610+
add_negotiation_restrict_tips(transport->smart_options);
1611+
else {
1612+
struct strbuf config_name = STRBUF_INIT;
1613+
strbuf_addf(&config_name, "remote.%s.negotiationRestrict", remote->name);
1614+
warning(_("ignoring %s because the protocol does not support it"),
1615+
config_name.buf);
1616+
strbuf_release(&config_name);
1617+
}
1618+
}
1619+
if (negotiation_require.nr) {
1620+
if (transport->smart_options)
1621+
transport->smart_options->negotiation_require = &negotiation_require;
1622+
else
1623+
warning(_("ignoring %s because the protocol does not support it"),
1624+
"--negotiation-require");
1625+
} else if (remote->negotiation_require.nr) {
1626+
if (transport->smart_options) {
1627+
transport->smart_options->negotiation_require = &remote->negotiation_require;
1628+
} else {
1629+
struct strbuf config_name = STRBUF_INIT;
1630+
strbuf_addf(&config_name, "remote.%s.negotiationRequire", remote->name);
1631+
warning(_("ignoring %s because the protocol does not support it"),
1632+
config_name.buf);
1633+
strbuf_release(&config_name);
1634+
}
16031635
}
16041636
return transport;
16051637
}
@@ -2525,6 +2557,10 @@ int cmd_fetch(int argc,
25252557
OPT_IPVERSION(&family),
25262558
OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
25272559
N_("report that we have only objects reachable from this object")),
2560+
OPT_STRING_LIST(0, "negotiation-restrict", &negotiation_tip, N_("revision"),
2561+
N_("report that we have only objects reachable from this object")),
2562+
OPT_STRING_LIST(0, "negotiation-require", &negotiation_require, N_("revision"),
2563+
N_("ensure this ref is always sent as a negotiation have")),
25282564
OPT_BOOL(0, "negotiate-only", &negotiate_only,
25292565
N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
25302566
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
@@ -2614,8 +2650,12 @@ int cmd_fetch(int argc,
26142650
config.display_format = DISPLAY_FORMAT_PORCELAIN;
26152651
}
26162652

2617-
if (negotiate_only && !negotiation_tip.nr)
2618-
die(_("--negotiate-only needs one or more --negotiation-tip=*"));
2653+
if (negotiate_only && !negotiation_tip.nr) {
2654+
/*
2655+
* Defer this check: remote.<name>.negotiationRestrict may
2656+
* provide defaults in prepare_transport().
2657+
*/
2658+
}
26192659

26202660
if (deepen_relative) {
26212661
if (deepen_relative < 0)
@@ -2704,6 +2744,9 @@ int cmd_fetch(int argc,
27042744
if (!remote)
27052745
die(_("must supply remote when using --negotiate-only"));
27062746
gtransport = prepare_transport(remote, 1, &filter_options);
2747+
if (!gtransport->smart_options ||
2748+
!gtransport->smart_options->negotiation_restrict_tips)
2749+
die(_("--negotiate-only needs one or more --negotiation-restrict=*"));
27072750
if (gtransport->smart_options) {
27082751
gtransport->smart_options->acked_commits = &acked_commits;
27092752
} else {

builtin/pull.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,12 @@ int cmd_pull(int argc,
999999
OPT_PASSTHRU_ARGV(0, "negotiation-tip", &opt_fetch, N_("revision"),
10001000
N_("report that we have only objects reachable from this object"),
10011001
0),
1002+
OPT_PASSTHRU_ARGV(0, "negotiation-restrict", &opt_fetch, N_("revision"),
1003+
N_("report that we have only objects reachable from this object"),
1004+
0),
1005+
OPT_PASSTHRU_ARGV(0, "negotiation-require", &opt_fetch, N_("revision"),
1006+
N_("ensure this ref is always sent as a negotiation have"),
1007+
0),
10021008
OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
10031009
N_("check for forced-updates on all updated branches")),
10041010
OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,

0 commit comments

Comments
 (0)