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

Adding a second remote to a shallow, single-branch 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 and single-branch in the first place, 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>
seen
Harald Nordgren 2026-10-10 08:02:14 +00:00 committed by Junio C Hamano
parent ee8f93969c
commit 2b6e751fc0
3 changed files with 71 additions and 2 deletions

View File

@ -52,6 +52,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.
+
@ -74,7 +79,8 @@ With `--limited-fetch` option, instead of a `remote.<name>.fetch` refspec
that tracks all branches, `remote.<name>.refmap` 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.

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) {
int 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) {

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.refmap &&
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.refmap
)
'

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 &&