fetch: add new config option fetch.all

Introduce a boolean configuration option fetch.all which allows to
fetch all available remotes by default. The config option can be
overridden by explicitly specifying a remote or by using --no-all.
The behavior for --all is unchanged and calling git-fetch with --all
and a remote will still result in an error.

Additionally, describe the configuration variable in the config
documentation and implement new tests to cover the expected behavior.
Also add --no-all to the command-line documentation of git-fetch.

Signed-off-by: Tamino Bauknecht <dev@tb6.eu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Tamino Bauknecht 2024-01-08 22:13:55 +01:00 committed by Junio C Hamano
parent a26002b628
commit 39487a1510
4 changed files with 186 additions and 3 deletions

View file

@ -50,6 +50,12 @@ fetch.pruneTags::
refs. See also `remote.<name>.pruneTags` and the PRUNING
section of linkgit:git-fetch[1].
fetch.all::
If true, fetch will attempt to update all available remotes.
This behavior can be overridden by passing `--no-all` or by
explicitly specifying one or more remote(s) to fetch from.
Defaults to false.
fetch.output::
Control how ref update status is printed. Valid values are
`full` and `compact`. Default value is `full`. See the

View file

@ -1,5 +1,6 @@
--all::
Fetch all remotes.
--[no-]all::
Fetch all remotes. This overrides the configuration variable
`fetch.all`.
-a::
--append::

View file

@ -102,6 +102,7 @@ static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
struct fetch_config {
enum display_format display_format;
int all;
int prune;
int prune_tags;
int show_forced_updates;
@ -115,6 +116,11 @@ static int git_fetch_config(const char *k, const char *v,
{
struct fetch_config *fetch_config = cb;
if (!strcmp(k, "fetch.all")) {
fetch_config->all = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "fetch.prune")) {
fetch_config->prune = git_config_bool(k, v);
return 0;
@ -2132,7 +2138,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
int all = 0, multiple = 0;
int all = -1, multiple = 0;
int result = 0;
int prune_tags_ok = 1;
int enable_auto_gc = 1;
@ -2337,11 +2343,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
fetch_bundle_uri(the_repository, bundle_uri, NULL))
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
if (all < 0) {
/*
* no --[no-]all given;
* only use config option if no remote was explicitly specified
*/
all = (!argc) ? config.all : 0;
}
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
else if (argc > 1)
die(_("fetch --all does not make sense with refspecs"));
(void) for_each_remote(get_one_remote_for_fetch, &list);
/* do not do fetch_multiple() of one */

View file

@ -24,6 +24,15 @@ setup_repository () {
)
}
setup_test_clone () {
test_dir="$1" &&
git clone one "$test_dir" &&
for r in one two three
do
git -C "$test_dir" remote add "$r" "../$r" || return 1
done
}
test_expect_success setup '
setup_repository one &&
setup_repository two &&
@ -209,4 +218,156 @@ test_expect_success 'git fetch --multiple --jobs=0 picks a default' '
git fetch --multiple --jobs=0)
'
create_fetch_all_expect () {
cat >expect <<-\EOF
one/main
one/side
origin/HEAD -> origin/main
origin/main
origin/side
three/another
three/main
three/side
two/another
two/main
two/side
EOF
}
for fetch_all in true false
do
test_expect_success "git fetch --all (works with fetch.all = $fetch_all)" '
test_dir="test_fetch_all_$fetch_all" &&
setup_test_clone "$test_dir" &&
(
cd "$test_dir" &&
git config fetch.all $fetch_all &&
git fetch --all &&
create_fetch_all_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
done
test_expect_success 'git fetch (fetch all remotes with fetch.all = true)' '
setup_test_clone test9 &&
(
cd test9 &&
git config fetch.all true &&
git fetch &&
git branch -r >actual &&
create_fetch_all_expect &&
test_cmp expect actual
)
'
create_fetch_one_expect () {
cat >expect <<-\EOF
one/main
one/side
origin/HEAD -> origin/main
origin/main
origin/side
EOF
}
test_expect_success 'git fetch one (explicit remote overrides fetch.all)' '
setup_test_clone test10 &&
(
cd test10 &&
git config fetch.all true &&
git fetch one &&
create_fetch_one_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
create_fetch_two_as_origin_expect () {
cat >expect <<-\EOF
origin/HEAD -> origin/main
origin/another
origin/main
origin/side
EOF
}
test_expect_success 'git config fetch.all false (fetch only default remote)' '
setup_test_clone test11 &&
(
cd test11 &&
git config fetch.all false &&
git remote set-url origin ../two &&
git fetch &&
create_fetch_two_as_origin_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
for fetch_all in true false
do
test_expect_success "git fetch --no-all (fetch only default remote with fetch.all = $fetch_all)" '
test_dir="test_no_all_fetch_all_$fetch_all" &&
setup_test_clone "$test_dir" &&
(
cd "$test_dir" &&
git config fetch.all $fetch_all &&
git remote set-url origin ../two &&
git fetch --no-all &&
create_fetch_two_as_origin_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
done
test_expect_success 'git fetch --no-all (fetch only default remote without fetch.all)' '
setup_test_clone test12 &&
(
cd test12 &&
git config --unset-all fetch.all || true &&
git remote set-url origin ../two &&
git fetch --no-all &&
create_fetch_two_as_origin_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
test_expect_success 'git fetch --all --no-all (fetch only default remote)' '
setup_test_clone test13 &&
(
cd test13 &&
git remote set-url origin ../two &&
git fetch --all --no-all &&
create_fetch_two_as_origin_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
test_expect_success 'git fetch --no-all one (fetch only explicit remote)' '
setup_test_clone test14 &&
(
cd test14 &&
git fetch --no-all one &&
create_fetch_one_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
test_expect_success 'git fetch --no-all --all (fetch all remotes)' '
setup_test_clone test15 &&
(
cd test15 &&
git fetch --no-all --all &&
create_fetch_all_expect &&
git branch -r >actual &&
test_cmp expect actual
)
'
test_done