Skip to content

Commit 8f0700d

Browse files
jlehmanngitster
authored andcommitted
fetch/pull: Add the 'on-demand' value to the --recurse-submodules option
Until now the --recurse-submodules option could only be used to either fetch all populated submodules recursively or to disable recursion completely. As fetch and pull now by default just fetch those submodules for which new commits have been fetched in the superproject, a command line option to enforce that behavior is needed to be able to override configuration settings. Signed-off-by: Jens Lehmann <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 88a2197 commit 8f0700d

File tree

7 files changed

+114
-10
lines changed

7 files changed

+114
-10
lines changed

Documentation/fetch-options.txt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,19 @@ ifndef::git-pull[]
6565
specified with the remote.<name>.tagopt setting. See
6666
linkgit:git-config[1].
6767

68-
--[no-]recurse-submodules::
69-
This option controls if new commits of all populated submodules should
70-
be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]).
68+
--recurse-submodules[=yes|on-demand|no]::
69+
This option controls if and under what conditions new commits of
70+
populated submodules should be fetched too. It can be used as a
71+
boolean option to completely disable recursion when set to 'no' or to
72+
unconditionally recurse into all populated submodules when set to
73+
'yes', which is the default when this option is used without any
74+
value. Use 'on-demand' to only recurse into a populated submodule
75+
when the superproject retrieves a commit that updates the submodule's
76+
reference.
77+
78+
--no-recurse-submodules::
79+
Disable recursive fetching of submodules (this has the same effect as
80+
using the '--recurse-submodules=no' option).
7181

7282
--submodule-prefix=<path>::
7383
Prepend <path> to paths printed in informative messages

Documentation/git-pull.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ must be given before the options meant for 'git fetch'.
8484
--verbose::
8585
Pass --verbose to git-fetch and git-merge.
8686

87-
--[no-]recurse-submodules::
87+
--[no-]recurse-submodules[=yes|on-demand|no]::
8888
This option controls if new commits of all populated submodules should
8989
be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]).
9090
That might be necessary to get the data needed for merging submodule

builtin/fetch.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ static struct transport *transport;
3838
static const char *submodule_prefix = "";
3939
static const char *recurse_submodules_default;
4040

41+
static int option_parse_recurse_submodules(const struct option *opt,
42+
const char *arg, int unset)
43+
{
44+
if (unset) {
45+
recurse_submodules = RECURSE_SUBMODULES_OFF;
46+
} else {
47+
if (arg)
48+
recurse_submodules = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
49+
else
50+
recurse_submodules = RECURSE_SUBMODULES_ON;
51+
}
52+
return 0;
53+
}
54+
4155
static struct option builtin_fetch_options[] = {
4256
OPT__VERBOSITY(&verbosity),
4357
OPT_BOOLEAN(0, "all", &all,
@@ -55,9 +69,9 @@ static struct option builtin_fetch_options[] = {
5569
"do not fetch all tags (--no-tags)", TAGS_UNSET),
5670
OPT_BOOLEAN('p', "prune", &prune,
5771
"prune remote-tracking branches no longer on remote"),
58-
OPT_SET_INT(0, "recurse-submodules", &recurse_submodules,
72+
{ OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand",
5973
"control recursive fetching of submodules",
60-
RECURSE_SUBMODULES_ON),
74+
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
6175
OPT_BOOLEAN(0, "dry-run", &dry_run,
6276
"dry run"),
6377
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
@@ -817,6 +831,8 @@ static void add_options_to_argv(int *argc, const char **argv)
817831
argv[(*argc)++] = "--keep";
818832
if (recurse_submodules == RECURSE_SUBMODULES_ON)
819833
argv[(*argc)++] = "--recurse-submodules";
834+
else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
835+
argv[(*argc)++] = "--recurse-submodules=on-demand";
820836
if (verbosity >= 2)
821837
argv[(*argc)++] = "-v";
822838
if (verbosity >= 1)
@@ -965,7 +981,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
965981
add_options_to_argv(&num_options, options);
966982
result = fetch_populated_submodules(num_options, options,
967983
submodule_prefix,
968-
recurse_submodules == RECURSE_SUBMODULES_ON,
984+
recurse_submodules,
969985
verbosity < 0);
970986
}
971987

git-pull.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ do
108108
--recurse-submodules)
109109
recurse_submodules=--recurse-submodules
110110
;;
111+
--recurse-submodules=*)
112+
recurse_submodules="$1"
113+
;;
111114
--no-recurse-submodules)
112115
recurse_submodules=--no-recurse-submodules
113116
;;

submodule.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ void check_for_new_submodule_commits(unsigned char new_sha1[20])
330330
}
331331

332332
int fetch_populated_submodules(int num_options, const char **options,
333-
const char *prefix, int ignore_config,
333+
const char *prefix, int command_line_option,
334334
int quiet)
335335
{
336336
int i, result = 0, argc = 0, default_argc;
@@ -376,7 +376,7 @@ int fetch_populated_submodules(int num_options, const char **options,
376376
name = name_for_path->util;
377377

378378
default_argv = "yes";
379-
if (!ignore_config) {
379+
if (command_line_option == RECURSE_SUBMODULES_DEFAULT) {
380380
struct string_list_item *fetch_recurse_submodules_option;
381381
fetch_recurse_submodules_option = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name);
382382
if (fetch_recurse_submodules_option) {
@@ -391,6 +391,10 @@ int fetch_populated_submodules(int num_options, const char **options,
391391
default_argv = "on-demand";
392392
}
393393
}
394+
} else if (command_line_option == RECURSE_SUBMODULES_ON_DEMAND) {
395+
if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
396+
continue;
397+
default_argv = "on-demand";
394398
}
395399

396400
strbuf_addf(&submodule_path, "%s/%s", work_tree, ce->name);

submodule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ void show_submodule_summary(FILE *f, const char *path,
2424
void set_config_fetch_recurse_submodules(int value);
2525
void check_for_new_submodule_commits(unsigned char new_sha1[20]);
2626
int fetch_populated_submodules(int num_options, const char **options,
27-
const char *prefix, int ignore_config,
27+
const char *prefix, int command_line_option,
2828
int quiet);
2929
unsigned is_submodule_modified(const char *path, int ignore_untracked);
3030
int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],

t/t5526-fetch-submodules.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,75 @@ test_expect_success "Recursion picks up all submodules when necessary" '
301301
test_cmp expect.out actual.out
302302
'
303303

304+
test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" '
305+
add_upstream_commit &&
306+
(
307+
cd submodule &&
308+
(
309+
cd deepsubmodule &&
310+
git fetch &&
311+
git checkout -q FETCH_HEAD
312+
) &&
313+
head1=$(git rev-parse --short HEAD^) &&
314+
git add deepsubmodule &&
315+
git commit -m "new deepsubmodule"
316+
head2=$(git rev-parse --short HEAD) &&
317+
echo "From $pwd/submodule" > ../expect.err.sub &&
318+
echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub
319+
) &&
320+
(
321+
cd downstream &&
322+
git config fetch.recurseSubmodules true &&
323+
git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
324+
git config --unset fetch.recurseSubmodules
325+
) &&
326+
! test -s actual.out &&
327+
! test -s actual.err
328+
'
329+
330+
test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" '
331+
head1=$(git rev-parse --short HEAD) &&
332+
git add submodule &&
333+
git commit -m "new submodule" &&
334+
head2=$(git rev-parse --short HEAD) &&
335+
tail -2 expect.err > expect.err.deepsub &&
336+
echo "From $pwd/." > expect.err &&
337+
echo " $head1..$head2 master -> origin/master" >> expect.err
338+
cat expect.err.sub >> expect.err &&
339+
cat expect.err.deepsub >> expect.err &&
340+
(
341+
cd downstream &&
342+
git config fetch.recurseSubmodules false &&
343+
(
344+
cd submodule &&
345+
git config -f .gitmodules submodule.deepsubmodule.fetchRecursive false
346+
) &&
347+
git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err &&
348+
git config --unset fetch.recurseSubmodules
349+
(
350+
cd submodule &&
351+
git config --unset -f .gitmodules submodule.deepsubmodule.fetchRecursive
352+
)
353+
) &&
354+
test_cmp expect.out actual.out &&
355+
test_cmp expect.err actual.err
356+
'
357+
358+
test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" '
359+
add_upstream_commit &&
360+
head1=$(git rev-parse --short HEAD) &&
361+
echo a >> file &&
362+
git add file &&
363+
git commit -m "new file" &&
364+
head2=$(git rev-parse --short HEAD) &&
365+
echo "From $pwd/." > expect.err.file &&
366+
echo " $head1..$head2 master -> origin/master" >> expect.err.file &&
367+
(
368+
cd downstream &&
369+
git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err
370+
) &&
371+
! test -s actual.out &&
372+
test_cmp expect.err.file actual.err
373+
'
374+
304375
test_done

0 commit comments

Comments
 (0)