remote: default to --limited-fetch in a shallow repository

Adding a second remote to a shallow clone used to still fetch every
branch that remote has, since "git remote add" always set up a
wildcard remote.<name>.fetch refspec regardless of how shallow the
repository already was. That defeats the purpose of having cloned
shallow in the first place (for example with --single-branch), and
can make a plain "git fetch" on that remote hang or take a very long
time on a repository with many branches.

Turn --limited-fetch on by default when the repository is already
shallow and neither -t/--track nor --mirror was given, so that
adding a remote there does not by itself commit to following every
branch it has. --no-limited-fetch keeps the previous behavior for
whoever wants it.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Harald Nordgren authored and Junio C Hamano committed 2026-10-30 08:02:52 -07:00
1 parent 3cac0a73ee
commit 9271cd78cc
3 files changed
+71 -2

No files matched your search

+7 -1
View File
@@ -57,6 +57,11 @@ Add a remote named _<name>_ for the repository at
_<URL>_. The command `git fetch <name>` can then be used to create and
update remote-tracking branches `<name>/<branch>`.
+
If the repository is already a shallow repository (see linkgit:git-clone[1]
`--depth`) and neither `-t`, `--mirror` nor `--no-limited-fetch` is given,
`--limited-fetch` is turned on by default, so that `git fetch <name>` does
not need to negotiate history for every branch the remote has.
+
With `-f` option, `git fetch <name>` is run immediately after
the remote information is set up.
+
@@ -79,7 +84,8 @@ With `--limited-fetch` option, instead of a `remote.<name>.fetch` refspec
that tracks all branches, `remote.<name>.fetchRefmap` is set up so that a
refspec-less `git fetch <name>` only fetches branches our local branches
are built on. See the `--refmap` entry in linkgit:git-fetch[1] for
details.
details. `--no-limited-fetch` explicitly disables this, overriding the
shallow-repository default described above.
+
With `-m <master>` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
up to point at remote's _<master>_ branch. See also the set-head command.
+4 -1
View File
@@ -16,6 +16,7 @@
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
#include "shallow.h"
#include "odb.h"
#include "strvec.h"
#include "commit-reach.h"
@@ -238,7 +239,9 @@ static int add(int argc, const char **argv, const char *prefix,
if (!mirror || mirror & MIRROR_FETCH) {
bool use_limited_fetch = mirror == MIRROR_NONE && track.nr == 0 &&
limited_fetch == 1;
(limited_fetch == 1 ||
(limited_fetch == -1 &&
is_repository_shallow(the_repository)));
strbuf_reset(&buf);
if (use_limited_fetch) {
+60
View File
@@ -137,6 +137,66 @@ test_expect_success 'filters are listed by git remote -v only' '
test_grep ! "\[blob:none\]" out
'
test_expect_success 'add remote -t keeps an explicit refspec in a shallow repository' '
test_when_finished "rm -rf shallow-add" &&
git clone --no-local --depth=1 --branch main --single-branch \
one shallow-add &&
(
cd shallow-add &&
git remote add -t main upstream ../two &&
test_cmp_config "+refs/heads/main:refs/remotes/upstream/main" \
remote.upstream.fetch
)
'
test_expect_success 'add remote keeps the wildcard refspec in a full repository' '
test_when_finished "rm -rf full-add" &&
git clone --no-local one full-add &&
(
cd full-add &&
git remote add upstream ../two &&
test_cmp_config "+refs/heads/*:refs/remotes/upstream/*" \
remote.upstream.fetch
)
'
test_expect_success 'a remote added in a shallow repository defaults to --limited-fetch' '
test_when_finished "rm -rf shallow-add" &&
git clone --no-local --depth=1 --branch main --single-branch \
one shallow-add &&
(
cd shallow-add &&
git remote add upstream ../two &&
test_cmp_config "+refs/heads/*:refs/remotes/upstream/*" \
remote.upstream.fetchRefmap &&
test_must_fail git config get remote.upstream.fetch &&
git fetch upstream main &&
git branch --set-upstream-to=upstream/main &&
test_cmp_config upstream branch.main.remote &&
test_cmp_config refs/heads/main branch.main.merge &&
git fetch upstream &&
git for-each-ref --format="%(refname)" refs/remotes/upstream >actual &&
cat >expect <<-\EOF &&
refs/remotes/upstream/HEAD
refs/remotes/upstream/main
EOF
test_cmp expect actual
)
'
test_expect_success '--no-limited-fetch overrides the shallow-repository default' '
test_when_finished "rm -rf shallow-add" &&
git clone --no-local --depth=1 --branch main --single-branch \
one shallow-add &&
(
cd shallow-add &&
git remote add --no-limited-fetch upstream ../two &&
test_cmp_config "+refs/heads/*:refs/remotes/upstream/*" \
remote.upstream.fetch &&
test_must_fail git config get remote.upstream.fetchRefmap
)
'
test_expect_success '--limited-fetch works in a full repository too' '
test_when_finished "rm -rf full-add" &&
git clone --no-local one full-add &&