Skip to content

Commit 40b0eed

Browse files
committed
Merge branch 'hn/fetch-refmap' into seen
In a shallow repository, adding a new remote and fetching from it used to eagerly fetch all remote branches. The default refspec configured for remotes added in shallow repositories has been changed to rely on `remote.<name>.refmap` rather than `remote.<name>.fetch`, pulling only those remote branches tracked by local branches. * hn/fetch-refmap: remote: default to --limited-fetch in a shallow repository remote: add "git remote add --limited-fetch" fetch: infer branches to fetch from a refmap-only remote fetch: extract collect_upstream_from_remote() helper fetch: add remote.<name>.refmap
2 parents 92f6ae6 + 2b6e751 commit 40b0eed

11 files changed

Lines changed: 469 additions & 33 deletions

File tree

‎Documentation/config/remote.adoc‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ remote.<name>.fetch::
3333
The default set of "refspec" for linkgit:git-fetch[1]. See
3434
linkgit:git-fetch[1].
3535

36+
remote.<name>.refmap::
37+
The default value of the `--refmap` option for linkgit:git-fetch[1].
38+
Used to map remote refs being fetched to remote-tracking refs to
39+
store. If `remote.<name>.fetch` is not set either, a refspec-less
40+
fetch infers what to fetch from local branches built on this
41+
remote, instead of fetching every branch it has. See the
42+
`--refmap` entry in linkgit:git-fetch[1].
43+
3644
remote.<name>.push::
3745
The default set of "refspec" for linkgit:git-push[1]. See
3846
linkgit:git-push[1].

‎Documentation/fetch-options.adoc‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ endif::git-pull[]
244244
refspecs and rely entirely on the refspecs supplied as
245245
command-line arguments. See section on "Configured Remote-tracking
246246
Branches" for details.
247+
+
248+
When a refmap is active (from `--refmap` or `remote.<name>.refmap`) but
249+
nothing to fetch is specified on the command line, nor is there a
250+
`remote.<name>.fetch`, branches from the remote that are used as the
251+
`@{upstream}` of our local branches are fetched.
247252

248253
`-t`::
249254
`--tags`::

‎Documentation/git-remote.adoc‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
--------
1111
[synopsis]
1212
git remote [-v | --verbose]
13-
git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=(fetch|push)] <name> <URL>
13+
git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=(fetch|push)] [--[no-]limited-fetch] <name> <URL>
1414
git remote rename [--[no-]progress] <old> <new>
1515
git remote remove <name>
1616
git remote set-head <name> (-a | --auto | -d | --delete | <branch>)
@@ -57,6 +57,11 @@ Add a remote named _<name>_ for the repository at
5757
_<URL>_. The command `git fetch <name>` can then be used to create and
5858
update remote-tracking branches `<name>/<branch>`.
5959
+
60+
If the repository is already a shallow repository (see linkgit:git-clone[1]
61+
`--depth`) and neither `-t`, `--mirror` nor `--no-limited-fetch` is given,
62+
`--limited-fetch` is turned on by default, so that `git fetch <name>` does
63+
not need to negotiate history for every branch the remote has.
64+
+
6065
With `-f` option, `git fetch <name>` is run immediately after
6166
the remote information is set up.
6267
+
@@ -75,6 +80,13 @@ the `refs/remotes/<name>/` namespace, a refspec to track only _<branch>_
7580
is created. You can give more than one `-t <branch>` to track
7681
multiple branches without grabbing all branches.
7782
+
83+
With `--limited-fetch` option, instead of a `remote.<name>.fetch` refspec
84+
that tracks all branches, `remote.<name>.refmap` is set up so that a
85+
refspec-less `git fetch <name>` only fetches branches our local branches
86+
are built on. See the `--refmap` entry in linkgit:git-fetch[1] for
87+
details. `--no-limited-fetch` explicitly disables this, overriding the
88+
shallow-repository default described above.
89+
+
7890
With `-m <master>` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
7991
up to point at remote's _<master>_ branch. See also the set-head command.
8092
+

‎builtin/fetch.c‎

Lines changed: 90 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -553,22 +553,47 @@ static struct ref *get_ref_map(struct remote *remote,
553553
struct ref *rm;
554554
struct ref *ref_map = NULL;
555555
struct ref **tail = &ref_map;
556+
/*
557+
* The --refmap command line option, if given, takes precedence
558+
* over remote.<name>.refmap.
559+
*/
560+
struct refspec *effective_refmap =
561+
refmap.nr ? &refmap : remote ? &remote->refmap : NULL;
562+
struct refspec inferred_rs;
563+
int infer_from_refmap = 0;
556564

557565
/* opportunistically-updated references: */
558566
struct ref *orefs = NULL, **oref_tail = &orefs;
559567

560568
struct hashmap existing_refs;
561569
int existing_refs_populated = 0;
562570

571+
refspec_init_fetch(&inferred_rs, the_hash_algo);
572+
563573
filter_prefetch_refspec(rs);
564574
if (remote)
565575
filter_prefetch_refspec(&remote->fetch);
566576

577+
if (!rs->nr && remote && !remote->fetch.nr &&
578+
effective_refmap && effective_refmap->nr) {
579+
struct string_list tracked = STRING_LIST_INIT_DUP;
580+
struct string_list_item *item;
581+
582+
branches_tracking_remote(the_repository, remote, &tracked);
583+
for_each_string_list_item(item, &tracked)
584+
refspec_append(&inferred_rs, item->string);
585+
string_list_clear(&tracked, 0);
586+
587+
rs = &inferred_rs;
588+
infer_from_refmap = 1;
589+
}
590+
567591
if (rs->nr) {
568592
struct refspec *fetch_refspec;
569593

570594
for (i = 0; i < rs->nr; i++) {
571-
get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
595+
get_fetch_map(remote_refs, &rs->items[i], &tail,
596+
infer_from_refmap);
572597
if (rs->items[i].dst && rs->items[i].dst[0])
573598
*autotags = 1;
574599
}
@@ -596,13 +621,15 @@ static struct ref *get_ref_map(struct remote *remote,
596621
* by ref_remove_duplicates() in favor of one of these
597622
* opportunistic entries with FETCH_HEAD_IGNORE.
598623
*/
599-
if (refmap.nr)
600-
fetch_refspec = &refmap;
624+
if (effective_refmap && effective_refmap->nr)
625+
fetch_refspec = effective_refmap;
601626
else
602627
fetch_refspec = &remote->fetch;
603628

604629
for (i = 0; i < fetch_refspec->nr; i++)
605630
get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
631+
} else if (infer_from_refmap) {
632+
/* Already fully handled above. */
606633
} else if (refmap.nr) {
607634
die("--refmap option is only meaningful with command-line refspec(s)");
608635
} else {
@@ -698,6 +725,7 @@ static struct ref *get_ref_map(struct remote *remote,
698725
if (existing_refs_populated)
699726
hashmap_clear_and_free(&existing_refs, struct refname_hash_entry, ent);
700727

728+
refspec_clear(&inferred_rs);
701729
return ref_map;
702730
}
703731

@@ -1970,6 +1998,26 @@ static void collect_updated_tips(struct oidset *tips, struct ref *ref_map)
19701998
}
19711999
}
19722000

2001+
static int late_resolve_frh(const struct transport *transport,
2002+
const struct fetch_config *config)
2003+
{
2004+
/*
2005+
* See remote.c's handling of remote.<name>.followRemoteHEAD
2006+
* for the analogous, still-unresolved case.
2007+
*/
2008+
2009+
int follow_remote_head = FOLLOW_REMOTE_NEVER;
2010+
2011+
if (transport->remote->follow_remote_head)
2012+
follow_remote_head = transport->remote->follow_remote_head;
2013+
else if (config->follow_remote_head_seen)
2014+
follow_remote_head =
2015+
get_follow_remote_head(config->follow_remote_head_raw);
2016+
else
2017+
follow_remote_head = BUILTIN_FOLLOW_REMOTE_HEAD_DFLT;
2018+
return follow_remote_head;
2019+
}
2020+
19732021
static int do_fetch(struct transport *transport,
19742022
struct refspec *rs,
19752023
const struct fetch_config *config,
@@ -2007,31 +2055,48 @@ static int do_fetch(struct transport *transport,
20072055

20082056
if (rs->nr) {
20092057
refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
2058+
} else if (transport->remote->fetch.nr) {
2059+
struct string_list tracked = STRING_LIST_INIT_DUP;
2060+
struct string_list_item *item;
2061+
2062+
refspec_ref_prefixes(&transport->remote->fetch,
2063+
&transport_ls_refs_options.ref_prefixes);
2064+
2065+
follow_remote_head = late_resolve_frh(transport, config);
2066+
2067+
/*
2068+
* The configured refspec may not cover the current
2069+
* branch's upstream (e.g. a narrowed -t refspec), so
2070+
* make sure we can still fetch it regardless.
2071+
*/
2072+
collect_upstream_from_remote(the_repository, &tracked,
2073+
transport->remote, NULL);
2074+
for_each_string_list_item(item, &tracked)
2075+
strvec_push(&transport_ls_refs_options.ref_prefixes,
2076+
item->string);
2077+
string_list_clear(&tracked, 0);
20102078
} else {
2011-
struct branch *branch = branch_get(NULL);
2079+
/*
2080+
* The --refmap command line option, if given, takes
2081+
* precedence over remote.<name>.refmap.
2082+
*/
2083+
struct refspec *effective_refmap = refmap.nr ? &refmap :
2084+
&transport->remote->refmap;
2085+
struct string_list tracked = STRING_LIST_INIT_DUP;
2086+
struct string_list_item *item;
20122087

2013-
if (transport->remote->fetch.nr) {
2014-
refspec_ref_prefixes(&transport->remote->fetch,
2015-
&transport_ls_refs_options.ref_prefixes);
2016-
/*
2017-
* See remote.c's handling of remote.<name>.followRemoteHEAD
2018-
* for the analogous, still-unresolved case.
2019-
*/
2020-
if (transport->remote->follow_remote_head)
2021-
follow_remote_head = transport->remote->follow_remote_head;
2022-
else if (config->follow_remote_head_seen)
2023-
follow_remote_head = get_follow_remote_head(config->follow_remote_head_raw);
2024-
else
2025-
follow_remote_head = BUILTIN_FOLLOW_REMOTE_HEAD_DFLT;
2026-
}
2027-
if (branch && branch_has_merge_config(branch) &&
2028-
!strcmp(branch->remote_name, transport->remote->name)) {
2029-
int i;
2030-
for (i = 0; i < branch->merge_nr; i++) {
2031-
strvec_push(&transport_ls_refs_options.ref_prefixes,
2032-
branch->merge[i]->src);
2033-
}
2088+
if (effective_refmap->nr) {
2089+
branches_tracking_remote(the_repository,
2090+
transport->remote, &tracked);
2091+
follow_remote_head = late_resolve_frh(transport, config);
2092+
} else {
2093+
collect_upstream_from_remote(the_repository, &tracked,
2094+
transport->remote, NULL);
20342095
}
2096+
for_each_string_list_item(item, &tracked)
2097+
strvec_push(&transport_ls_refs_options.ref_prefixes,
2098+
item->string);
2099+
string_list_clear(&tracked, 0);
20352100

20362101
/*
20372102
* If there are no refs specified to fetch, then we just

‎builtin/remote.c‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "rebase.h"
1717
#include "refs.h"
1818
#include "refspec.h"
19+
#include "shallow.h"
1920
#include "odb.h"
2021
#include "strvec.h"
2122
#include "commit-reach.h"
@@ -179,6 +180,7 @@ static int add(int argc, const char **argv, const char *prefix,
179180
{
180181
int fetch = 0, fetch_tags = TAGS_DEFAULT;
181182
unsigned mirror = MIRROR_NONE;
183+
int limited_fetch = -1; /* unspecified */
182184
struct string_list track = STRING_LIST_INIT_NODUP;
183185
const char *master = NULL;
184186
struct remote *remote;
@@ -198,6 +200,8 @@ static int add(int argc, const char **argv, const char *prefix,
198200
OPT_CALLBACK_F(0, "mirror", &mirror, "(push|fetch)",
199201
N_("set up remote as a mirror to push to or fetch from"),
200202
PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt),
203+
OPT_BOOL(0, "limited-fetch", &limited_fetch,
204+
N_("fetch only the branches we build on, instead of every branch")),
201205
OPT_END()
202206
};
203207

@@ -211,6 +215,10 @@ static int add(int argc, const char **argv, const char *prefix,
211215
die(_("specifying a master branch makes no sense with --mirror"));
212216
if (mirror && !(mirror & MIRROR_FETCH) && track.nr)
213217
die(_("specifying branches to track makes sense only with fetch mirrors"));
218+
if (limited_fetch == 1 && track.nr)
219+
die(_("--limited-fetch does not make sense with -t/--track"));
220+
if (limited_fetch == 1 && mirror)
221+
die(_("--limited-fetch does not make sense with --mirror"));
214222

215223
name = argv[0];
216224
url = argv[1];
@@ -230,13 +238,24 @@ static int add(int argc, const char **argv, const char *prefix,
230238
repo_config_set(the_repository, buf.buf, url);
231239

232240
if (!mirror || mirror & MIRROR_FETCH) {
241+
int use_limited_fetch = mirror == MIRROR_NONE && track.nr == 0 &&
242+
(limited_fetch == 1 ||
243+
(limited_fetch == -1 &&
244+
is_repository_shallow(the_repository)));
245+
233246
strbuf_reset(&buf);
234-
strbuf_addf(&buf, "remote.%s.fetch", name);
235-
if (track.nr == 0)
236-
string_list_append(&track, "*");
237-
for (size_t i = 0; i < track.nr; i++) {
238-
add_branch(buf.buf, track.items[i].string,
239-
name, mirror, &buf2);
247+
if (use_limited_fetch) {
248+
strbuf_addf(&buf, "remote.%s.refmap", name);
249+
strbuf_reset(&buf2);
250+
strbuf_addf(&buf2, "+refs/heads/*:refs/remotes/%s/*", name);
251+
repo_config_set(the_repository, buf.buf, buf2.buf);
252+
} else {
253+
strbuf_addf(&buf, "remote.%s.fetch", name);
254+
if (track.nr == 0)
255+
string_list_append(&track, "*");
256+
for (size_t i = 0; i < track.nr; i++)
257+
add_branch(buf.buf, track.items[i].string,
258+
name, mirror, &buf2);
240259
}
241260
}
242261

‎remote.c‎

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ static struct remote *make_remote(struct remote_state *remote_state,
152152
ret->name = xstrndup(name, len);
153153
refspec_init_push(&ret->push, the_hash_algo);
154154
refspec_init_fetch(&ret->fetch, the_hash_algo);
155+
refspec_init_fetch(&ret->refmap, the_hash_algo);
155156
string_list_init_dup(&ret->server_options);
156157
string_list_init_dup(&ret->negotiation_restrict);
157158
string_list_init_dup(&ret->negotiation_include);
@@ -176,6 +177,7 @@ static void remote_clear(struct remote *remote)
176177

177178
refspec_clear(&remote->push);
178179
refspec_clear(&remote->fetch);
180+
refspec_clear(&remote->refmap);
179181

180182
free((char *)remote->receivepack);
181183
free((char *)remote->uploadpack);
@@ -539,6 +541,12 @@ static int handle_config(const char *key, const char *value,
539541
return -1;
540542
refspec_append(&remote->fetch, v);
541543
free(v);
544+
} else if (!strcmp(subkey, "refmap")) {
545+
char *v;
546+
if (git_config_string(&v, key, value))
547+
return -1;
548+
refspec_append(&remote->refmap, v);
549+
free(v);
542550
} else if (!strcmp(subkey, "receivepack")) {
543551
char *v;
544552
if (git_config_string(&v, key, value))
@@ -995,7 +1003,9 @@ void ref_push_report_free(struct ref_push_report *report)
9951003

9961004
int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
9971005
{
998-
return refspec_find_match(&remote->fetch, refspec);
1006+
if (remote->fetch.nr)
1007+
return refspec_find_match(&remote->fetch, refspec);
1008+
return refspec_find_match(&remote->refmap, refspec);
9991009
}
10001010

10011011
static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
@@ -1894,6 +1904,45 @@ int branch_merge_matches(struct branch *branch,
18941904
return refname_match(branch->merge[i]->src, refname);
18951905
}
18961906

1907+
void collect_upstream_from_remote(struct repository *repo,
1908+
struct string_list *tracked,
1909+
struct remote *remote,
1910+
const char *refname)
1911+
{
1912+
struct branch *branch = repo_branch_get(repo, refname);
1913+
1914+
if (!branch_has_merge_config(branch) ||
1915+
strcmp(branch->remote_name, remote->name))
1916+
return;
1917+
1918+
for (int i = 0; i < branch->merge_nr; i++)
1919+
string_list_insert(tracked, branch->merge[i]->src);
1920+
}
1921+
1922+
struct branches_tracking_remote_cb_data {
1923+
struct repository *repo;
1924+
struct remote *remote;
1925+
struct string_list *tracked;
1926+
};
1927+
1928+
static int add_if_tracking_remote(const struct reference *ref, void *cb_data)
1929+
{
1930+
struct branches_tracking_remote_cb_data *data = cb_data;
1931+
1932+
collect_upstream_from_remote(data->repo, data->tracked, data->remote,
1933+
ref->name);
1934+
return 0;
1935+
}
1936+
1937+
void branches_tracking_remote(struct repository *repo, struct remote *remote,
1938+
struct string_list *tracked)
1939+
{
1940+
struct branches_tracking_remote_cb_data data = { repo, remote, tracked };
1941+
1942+
refs_for_each_branch_ref(get_main_ref_store(repo),
1943+
add_if_tracking_remote, &data);
1944+
}
1945+
18971946
__attribute__((format (printf,2,3)))
18981947
static char *error_buf(struct strbuf *err, const char *fmt, ...)
18991948
{

0 commit comments

Comments
 (0)