Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions Documentation/config/remote.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,46 @@ 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` 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.

remote.<name>.negotiationRequire::
When negotiating with this remote during `git fetch` and `git push`,
the client advertises a list of commits that exist locally. In
repos with many references, this list of "haves" can be truncated.
Depending on data shape, dropping certain references may be
expensive. This multi-valued config option specifies ref patterns
whose tips should always be sent as "have" commits during fetch
negotiation with this remote.
+
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-require`
command-line option. If `--negotiation-require` is specified on the
command line, then the config values are not used.
+
This option is additive with the normal negotiation process: the
negotiation algorithm still runs and advertises its own selected commits,
but the refs matching `remote.<name>.negotiationRequire` are sent
unconditionally on top of those heuristically selected commits. This
option is also used during push negotiation when `push.negotiate` is
enabled.

remote.<name>.followRemoteHEAD::
How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`
when fetching using the configured refspecs of a remote.
Expand Down
27 changes: 27 additions & 0 deletions Documentation/fetch-options.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ the current repository has the same history as the source repository.
`.git/shallow`. This option updates `.git/shallow` and accepts such
refs.

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

`--negotiation-require=<revision>`::
Ensure that the given ref tip is always sent as a "have" line
during fetch negotiation, regardless of what the negotiation
algorithm selects. This is useful to guarantee that common
history reachable from specific refs is always considered, even
when `--negotiation-restrict` restricts the set of tips or when
the negotiation algorithm would otherwise skip them.
+
This option may be specified more than once; if so, each ref is sent
unconditionally.
+
The argument may be an exact ref name (e.g. `refs/heads/release`) or a
glob pattern (e.g. `refs/heads/release/{asterisk}`). The pattern syntax
is the same as for `--negotiation-restrict`.
+
If `--negotiation-restrict` is used, the have set is first restricted by
that option and then increased to include the tips specified by
`--negotiation-require`.
+
If this option is not specified on the command line, then any
`remote.<name>.negotiationRequire` config values for the current remote
are used instead.

`--negotiate-only`::
Do not fetch anything from the server, and instead print the
ancestors of the provided `--negotiation-tip=` arguments,
Expand Down
59 changes: 51 additions & 8 deletions builtin/fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static struct transport *gsecondary;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static struct string_list negotiation_require = STRING_LIST_INIT_NODUP;

struct fetch_config {
enum display_format display_format;
Expand Down Expand Up @@ -1534,7 +1535,7 @@ static int add_oid(const struct reference *ref, void *cb_data)
return 0;
}

static void add_negotiation_tips(struct git_transport_options *smart_options)
static void add_negotiation_restrict_tips(struct git_transport_options *smart_options)
{
struct oid_array *oids = xcalloc(1, sizeof(*oids));
int i;
Expand All @@ -1558,10 +1559,10 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
refs_for_each_ref_ext(get_main_ref_store(the_repository),
add_oid, oids, &opts);
if (old_nr == oids->nr)
warning("ignoring --negotiation-tip=%s because it does not match any refs",
s);
warning(_("ignoring %s=%s because it does not match any refs"),
"--negotiation-restrict", s);
}
smart_options->negotiation_tips = oids;
smart_options->negotiation_restrict_tips = oids;
}

static struct transport *prepare_transport(struct remote *remote, int deepen,
Expand Down Expand Up @@ -1597,9 +1598,40 @@ static struct transport *prepare_transport(struct remote *remote, int deepen,
}
if (negotiation_tip.nr) {
if (transport->smart_options)
add_negotiation_tips(transport->smart_options);
add_negotiation_restrict_tips(transport->smart_options);
else
warning("ignoring --negotiation-tip because the protocol does not support it");
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_tip, 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);
}
}
if (negotiation_require.nr) {
if (transport->smart_options)
transport->smart_options->negotiation_require = &negotiation_require;
else
warning(_("ignoring %s because the protocol does not support it"),
"--negotiation-require");
} else if (remote->negotiation_require.nr) {
if (transport->smart_options) {
transport->smart_options->negotiation_require = &remote->negotiation_require;
} else {
struct strbuf config_name = STRBUF_INIT;
strbuf_addf(&config_name, "remote.%s.negotiationRequire", remote->name);
warning(_("ignoring %s because the protocol does not support it"),
config_name.buf);
strbuf_release(&config_name);
}
}
return transport;
}
Expand Down Expand Up @@ -2567,6 +2599,10 @@ int cmd_fetch(int argc,
OPT_IPVERSION(&family),
OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
N_("report that we have only objects reachable from this object")),
OPT_STRING_LIST(0, "negotiation-restrict", &negotiation_tip, N_("revision"),
N_("report that we have only objects reachable from this object")),
OPT_STRING_LIST(0, "negotiation-require", &negotiation_require, N_("revision"),
N_("ensure this ref is always sent as a negotiation have")),
OPT_BOOL(0, "negotiate-only", &negotiate_only,
N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
Expand Down Expand Up @@ -2656,8 +2692,12 @@ int cmd_fetch(int argc,
config.display_format = DISPLAY_FORMAT_PORCELAIN;
}

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

if (deepen_relative) {
if (deepen_relative < 0)
Expand Down Expand Up @@ -2746,6 +2786,9 @@ 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(_("--negotiate-only needs one or more --negotiation-restrict=*"));
if (gtransport->smart_options) {
gtransport->smart_options->acked_commits = &acked_commits;
} else {
Expand Down
6 changes: 6 additions & 0 deletions builtin/pull.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,12 @@ int cmd_pull(int argc,
OPT_PASSTHRU_ARGV(0, "negotiation-tip", &opt_fetch, N_("revision"),
N_("report that we have only objects reachable from this object"),
0),
OPT_PASSTHRU_ARGV(0, "negotiation-restrict", &opt_fetch, N_("revision"),
N_("report that we have only objects reachable from this object"),
0),
OPT_PASSTHRU_ARGV(0, "negotiation-require", &opt_fetch, N_("revision"),
N_("ensure this ref is always sent as a negotiation have"),
0),
OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
N_("check for forced-updates on all updated branches")),
OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
Expand Down
Loading
Loading