Skip to content

Commit c5558f8

Browse files
committed
fetch: allow explicit --refmap to override configuration
Since the introduction of opportunisitic updates of remote-tracking branches, started at around f269048 (fetch: opportunistically update tracking refs, 2013-05-11) with a few updates in v1.8.4 era, the remote.*.fetch configuration always kicks in even when a refspec to specify what to fetch is given on the command line, and there is no way to disable or override it per-invocation. Teach the command to pay attention to the --refmap=<lhs>:<rhs> command-line options that can be used to override the use of configured remote.*.fetch as the refmap. Signed-off-by: Junio C Hamano <[email protected]> ---
1 parent fcb14b0 commit c5558f8

File tree

4 files changed

+81
-3
lines changed

4 files changed

+81
-3
lines changed

Documentation/fetch-options.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ endif::git-pull[]
7272
setting. See linkgit:git-config[1].
7373

7474
ifndef::git-pull[]
75+
--refmap=<refspec>::
76+
When fetching refs listed on the command line, use the
77+
specified refspec (can be given more than once) to map the
78+
refs to remote-tracking branches, instead of the values of
79+
`remote.*.fetch` configuration variables for the remote
80+
repository. See section on "Configured Remote-tracking
81+
Branches" for details.
82+
7583
-t::
7684
--tags::
7785
Fetch all tags from the remote (i.e., fetch remote tags

Documentation/git-fetch.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ This configuration is used in two ways:
9595
only used to decide _where_ the refs that are fetched are stored
9696
by acting as a mapping.
9797

98+
The latter use of the `remote.<repository>.fetch` values can be
99+
overridden by giving the `--refmap=<refspec>` parameter(s) on the
100+
command line.
101+
98102

99103
EXAMPLES
100104
--------

builtin/fetch.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ static struct transport *gsecondary;
4545
static const char *submodule_prefix = "";
4646
static const char *recurse_submodules_default;
4747
static int shown_url = 0;
48+
static int refmap_alloc, refmap_nr;
49+
static const char **refmap_array;
4850

4951
static int option_parse_recurse_submodules(const struct option *opt,
5052
const char *arg, int unset)
@@ -69,6 +71,19 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
6971
return 0;
7072
}
7173

74+
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
75+
{
76+
ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
77+
78+
/*
79+
* "git fetch --refmap='' origin foo"
80+
* can be used to tell the command not to store anywhere
81+
*/
82+
if (*arg)
83+
refmap_array[refmap_nr++] = arg;
84+
return 0;
85+
}
86+
7287
static struct option builtin_fetch_options[] = {
7388
OPT__VERBOSITY(&verbosity),
7489
OPT_BOOL(0, "all", &all,
@@ -107,6 +122,8 @@ static struct option builtin_fetch_options[] = {
107122
N_("default mode for recursion"), PARSE_OPT_HIDDEN },
108123
OPT_BOOL(0, "update-shallow", &update_shallow,
109124
N_("accept refs that update .git/shallow")),
125+
{ OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
126+
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
110127
OPT_END()
111128
};
112129

@@ -278,6 +295,9 @@ static struct ref *get_ref_map(struct transport *transport,
278295
const struct ref *remote_refs = transport_get_remote_refs(transport);
279296

280297
if (refspec_count) {
298+
struct refspec *fetch_refspec;
299+
int fetch_refspec_nr;
300+
281301
for (i = 0; i < refspec_count; i++) {
282302
get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
283303
if (refspecs[i].dst && refspecs[i].dst[0])
@@ -307,12 +327,21 @@ static struct ref *get_ref_map(struct transport *transport,
307327
* by ref_remove_duplicates() in favor of one of these
308328
* opportunistic entries with FETCH_HEAD_IGNORE.
309329
*/
310-
for (i = 0; i < transport->remote->fetch_refspec_nr; i++)
311-
get_fetch_map(ref_map, &transport->remote->fetch[i],
312-
&oref_tail, 1);
330+
if (refmap_array) {
331+
fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
332+
fetch_refspec_nr = refmap_nr;
333+
} else {
334+
fetch_refspec = transport->remote->fetch;
335+
fetch_refspec_nr = transport->remote->fetch_refspec_nr;
336+
}
337+
338+
for (i = 0; i < fetch_refspec_nr; i++)
339+
get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
313340

314341
if (tags == TAGS_SET)
315342
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
343+
} else if (refmap_array) {
344+
die("--refmap option is only meaningful with command-line refspec(s).");
316345
} else {
317346
/* Use the defaults */
318347
struct remote *remote = transport->remote;

t/t5510-fetch.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,43 @@ test_expect_success 'explicit pull should update tracking' '
447447
)
448448
'
449449

450+
test_expect_success 'explicit --refmap is allowed only with command-line refspec' '
451+
cd "$D" &&
452+
(
453+
cd three &&
454+
test_must_fail git fetch --refmap="*:refs/remotes/none/*"
455+
)
456+
'
457+
458+
test_expect_success 'explicit --refmap option overrides remote.*.fetch' '
459+
cd "$D" &&
460+
git branch -f side &&
461+
(
462+
cd three &&
463+
git update-ref refs/remotes/origin/master base-origin-master &&
464+
o=$(git rev-parse --verify refs/remotes/origin/master) &&
465+
git fetch --refmap="refs/heads/*:refs/remotes/other/*" origin master &&
466+
n=$(git rev-parse --verify refs/remotes/origin/master) &&
467+
test "$o" = "$n" &&
468+
test_must_fail git rev-parse --verify refs/remotes/origin/side &&
469+
git rev-parse --verify refs/remotes/other/master
470+
)
471+
'
472+
473+
test_expect_success 'explicitly empty --refmap option disables remote.*.fetch' '
474+
cd "$D" &&
475+
git branch -f side &&
476+
(
477+
cd three &&
478+
git update-ref refs/remotes/origin/master base-origin-master &&
479+
o=$(git rev-parse --verify refs/remotes/origin/master) &&
480+
git fetch --refmap="" origin master &&
481+
n=$(git rev-parse --verify refs/remotes/origin/master) &&
482+
test "$o" = "$n" &&
483+
test_must_fail git rev-parse --verify refs/remotes/origin/side
484+
)
485+
'
486+
450487
test_expect_success 'configured fetch updates tracking' '
451488
452489
cd "$D" &&

0 commit comments

Comments
 (0)