Skip to content

Commit a668853

Browse files
committed
Merge branch 'jc/fetch-pull-refmap'
* jc/fetch-pull-refmap: docs: Explain the purpose of fetch's and pull's <refspec> parameter. fetch: allow explicit --refmap to override configuration fetch doc: add a section on configured remote-tracking branches fetch doc: remove "short-cut" section fetch doc: update refspec format description fetch doc: on pulling multiple refspecs fetch doc: remove notes on outdated "mixed layout" fetch doc: update note on '+' in front of the refspec fetch doc: move FETCH_HEAD material lower and add an example fetch doc: update introductory part for clarity
2 parents 9fe49ae + db4e411 commit a668853

File tree

5 files changed

+191
-60
lines changed

5 files changed

+191
-60
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: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,31 @@ SYNOPSIS
1717

1818
DESCRIPTION
1919
-----------
20-
Fetches named heads or tags from one or more other repositories,
21-
along with the objects necessary to complete them.
20+
Fetch branches and/or tags (collectively, "refs") from one or more
21+
other repositories, along with the objects necessary to complete their
22+
histories. Remote-tracking branches are updated (see the description
23+
of <refspec> below for ways to control this behavior).
2224

23-
The ref names and their object names of fetched refs are stored
24-
in `.git/FETCH_HEAD`. This information is left for a later merge
25-
operation done by 'git merge'.
26-
27-
By default, tags are auto-followed. This means that when fetching
28-
from a remote, any tags on the remote that point to objects that exist
29-
in the local repository are fetched. The effect is to fetch tags that
25+
By default, any tag that points into the histories being fetched is
26+
also fetched; the effect is to fetch tags that
3027
point at branches that you are interested in. This default behavior
31-
can be changed by using the --tags or --no-tags options, by
32-
configuring remote.<name>.tagopt, or by using a refspec that fetches
33-
tags explicitly.
28+
can be changed by using the --tags or --no-tags options or by
29+
configuring remote.<name>.tagopt. By using a refspec that fetches tags
30+
explicitly, you can fetch tags that do not point into branches you
31+
are interested in as well.
3432

35-
'git fetch' can fetch from either a single named repository,
33+
'git fetch' can fetch from either a single named repository or URL,
3634
or from several repositories at once if <group> is given and
3735
there is a remotes.<group> entry in the configuration file.
3836
(See linkgit:git-config[1]).
3937

4038
When no remote is specified, by default the `origin` remote will be used,
4139
unless there's an upstream branch configured for the current branch.
4240

41+
The names of refs that are fetched, together with the object names
42+
they point at, are written to `.git/FETCH_HEAD`. This information
43+
may be used by scripts or other git commands, such as linkgit:git-pull[1].
44+
4345
OPTIONS
4446
-------
4547
include::fetch-options.txt[]
@@ -49,6 +51,55 @@ include::pull-fetch-param.txt[]
4951
include::urls-remotes.txt[]
5052

5153

54+
CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]]
55+
-------------------------------------------
56+
57+
You often interact with the same remote repository by
58+
regularly and repeatedly fetching from it. In order to keep track
59+
of the progress of such a remote repository, `git fetch` allows you
60+
to configure `remote.<repository>.fetch` configuration variables.
61+
62+
Typically such a variable may look like this:
63+
64+
------------------------------------------------
65+
[remote "origin"]
66+
fetch = +refs/heads/*:refs/remotes/origin/*
67+
------------------------------------------------
68+
69+
This configuration is used in two ways:
70+
71+
* When `git fetch` is run without specifying what branches
72+
and/or tags to fetch on the command line, e.g. `git fetch origin`
73+
or `git fetch`, `remote.<repository>.fetch` values are used as
74+
the refspecs---they specify which refs to fetch and which local refs
75+
to update. The example above will fetch
76+
all branches that exist in the `origin` (i.e. any ref that matches
77+
the left-hand side of the value, `refs/heads/*`) and update the
78+
corresponding remote-tracking branches in the `refs/remotes/origin/*`
79+
hierarchy.
80+
81+
* When `git fetch` is run with explicit branches and/or tags
82+
to fetch on the command line, e.g. `git fetch origin master`, the
83+
<refspec>s given on the command line determine what are to be
84+
fetched (e.g. `master` in the example,
85+
which is a short-hand for `master:`, which in turn means
86+
"fetch the 'master' branch but I do not explicitly say what
87+
remote-tracking branch to update with it from the command line"),
88+
and the example command will
89+
fetch _only_ the 'master' branch. The `remote.<repository>.fetch`
90+
values determine which
91+
remote-tracking branch, if any, is updated. When used in this
92+
way, the `remote.<repository>.fetch` values do not have any
93+
effect in deciding _what_ gets fetched (i.e. the values are not
94+
used as refspecs when the command-line lists refspecs); they are
95+
only used to decide _where_ the refs that are fetched are stored
96+
by acting as a mapping.
97+
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+
102+
52103
EXAMPLES
53104
--------
54105

@@ -76,6 +127,19 @@ the local repository by fetching from the branches (respectively)
76127
The `pu` branch will be updated even if it is does not fast-forward,
77128
because it is prefixed with a plus sign; `tmp` will not be.
78129

130+
* Peek at a remote's branch, without configuring the remote in your local
131+
repository:
132+
+
133+
------------------------------------------------
134+
$ git fetch git://git.kernel.org/pub/scm/git/git.git maint
135+
$ git log FETCH_HEAD
136+
------------------------------------------------
137+
+
138+
The first command fetches the `maint` branch from the repository at
139+
`git://git.kernel.org/pub/scm/git/git.git` and the second command uses
140+
`FETCH_HEAD` to examine the branch with linkgit:git-log[1]. The fetched
141+
objects will eventually be removed by git's built-in housekeeping (see
142+
linkgit:git-gc[1]).
79143

80144
BUGS
81145
----

Documentation/pull-fetch-param.txt

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,23 @@ ifndef::git-pull[]
1212
endif::git-pull[]
1313

1414
<refspec>::
15-
The format of a <refspec> parameter is an optional plus
16-
`+`, followed by the source ref <src>, followed
17-
by a colon `:`, followed by the destination ref <dst>.
15+
Specifies which refs to fetch and which local refs to update.
16+
When no <refspec>s appear on the command line, the refs to fetch
17+
are read from `remote.<repository>.fetch` variables instead
18+
ifndef::git-pull[]
19+
(see <<CRTB,CONFIGURED REMOTE-TRACKING BRANCHES>> below).
20+
endif::git-pull[]
21+
ifdef::git-pull[]
22+
(see linkgit:git-fetch[1]).
23+
endif::git-pull[]
24+
+
25+
The format of a <refspec> parameter is an optional plus
26+
`+`, followed by the source ref <src>, followed
27+
by a colon `:`, followed by the destination ref <dst>.
28+
The colon can be omitted when <dst> is empty.
29+
+
30+
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`;
31+
it requests fetching everything up to the given tag.
1832
+
1933
The remote ref that matches <src>
2034
is fetched, and if <dst> is not empty string, the local
@@ -24,55 +38,34 @@ is updated even if it does not result in a fast-forward
2438
update.
2539
+
2640
[NOTE]
27-
If the remote branch from which you want to pull is
28-
modified in non-linear ways such as being rewound and
29-
rebased frequently, then a pull will attempt a merge with
30-
an older version of itself, likely conflict, and fail.
31-
It is under these conditions that you would want to use
32-
the `+` sign to indicate non-fast-forward updates will
33-
be needed. There is currently no easy way to determine
34-
or declare that a branch will be made available in a
35-
repository with this behavior; the pulling user simply
41+
When the remote branch you want to fetch is known to
42+
be rewound and rebased regularly, it is expected that
43+
its new tip will not be descendant of its previous tip
44+
(as stored in your remote-tracking branch the last time
45+
you fetched). You would want
46+
to use the `+` sign to indicate non-fast-forward updates
47+
will be needed for such branches. There is no way to
48+
determine or declare that a branch will be made available
49+
in a repository with this behavior; the pulling user simply
3650
must know this is the expected usage pattern for a branch.
37-
+
38-
[NOTE]
39-
You never do your own development on branches that appear
40-
on the right hand side of a <refspec> colon on `Pull:` lines;
41-
they are to be updated by 'git fetch'. If you intend to do
42-
development derived from a remote branch `B`, have a `Pull:`
43-
line to track it (i.e. `Pull: B:remote-B`), and have a separate
44-
branch `my-B` to do your development on top of it. The latter
45-
is created by `git branch my-B remote-B` (or its equivalent `git
46-
checkout -b my-B remote-B`). Run `git fetch` to keep track of
47-
the progress of the remote side, and when you see something new
48-
on the remote branch, merge it into your development branch with
49-
`git pull . remote-B`, while you are on `my-B` branch.
51+
ifdef::git-pull[]
5052
+
5153
[NOTE]
5254
There is a difference between listing multiple <refspec>
5355
directly on 'git pull' command line and having multiple
54-
`Pull:` <refspec> lines for a <repository> and running
56+
`remote.<repository>.fetch` entries in your configuration
57+
for a <repository> and running a
5558
'git pull' command without any explicit <refspec> parameters.
56-
<refspec> listed explicitly on the command line are always
59+
<refspec>s listed explicitly on the command line are always
5760
merged into the current branch after fetching. In other words,
58-
if you list more than one remote refs, you would be making
59-
an Octopus. While 'git pull' run without any explicit <refspec>
60-
parameter takes default <refspec>s from `Pull:` lines, it
61-
merges only the first <refspec> found into the current branch,
62-
after fetching all the remote refs. This is because making an
61+
if you list more than one remote ref, 'git pull' will create
62+
an Octopus merge. On the other hand, if you do not list any
63+
explicit <refspec> parameter on the command line, 'git pull'
64+
will fetch all the <refspec>s it finds in the
65+
`remote.<repository>.fetch` configuration and merge
66+
only the first <refspec> found into the current branch.
67+
This is because making an
6368
Octopus from remote refs is rarely done, while keeping track
6469
of multiple remote heads in one-go by fetching more than one
6570
is often useful.
66-
+
67-
Some short-cut notations are also supported.
68-
+
69-
* `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`;
70-
it requests fetching everything up to the given tag.
71-
ifndef::git-pull[]
72-
* A parameter <ref> without a colon fetches that ref into FETCH_HEAD,
73-
endif::git-pull[]
74-
ifdef::git-pull[]
75-
* A parameter <ref> without a colon merges <ref> into the current
76-
branch,
7771
endif::git-pull[]
78-
and updates the remote-tracking branches (if any).

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)