[PATCH v3 4/4] remote: default to --limited-fetch in a shallow repository
From: Harald Nordgren via GitGitGadget <hidden>
Date: 2026-09-25 10:50:12
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
From: Harald Nordgren <redacted> 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 <redacted> --- Documentation/git-remote.adoc | 8 ++++- builtin/remote.c | 5 ++- t/t5505-remote.sh | 59 +++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-remote.adoc b/Documentation/git-remote.adoc
index 74fbce6e0e..82b21eafa7 100644
--- a/Documentation/git-remote.adoc
+++ b/Documentation/git-remote.adoc@@ -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, plus the remote's default branch. See the `--refmap` entry -in linkgit:git-fetch[1] for details. +in linkgit:git-fetch[1] for 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.
diff --git a/builtin/remote.c b/builtin/remote.c
index f036dd5d6f..0cf1126976 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c@@ -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) {
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 0168d5abfe..9cb88d8806 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh@@ -137,6 +137,65 @@ 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 && + 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 && + git branch --set-upstream-to=upstream && + test_cmp_config upstream branch.main.remote && + test_cmp_config refs/heads/main branch.main.merge + ) +' + +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 &&
--
gitgitgadget