Skip to content

Commit 2e65591

Browse files
committed
Merge branch 'js/apply-partial-clone-filters-recursively'
"git clone --filter=... --recurse-submodules" only makes the top-level a partial clone, while submodules are fully cloned. This behaviour is changed to pass the same filter down to the submodules. * js/apply-partial-clone-filters-recursively: clone, submodule: pass partial clone filters to submodules
2 parents d21d5dd + f05da2b commit 2e65591

File tree

8 files changed

+175
-8
lines changed

8 files changed

+175
-8
lines changed

Documentation/config/clone.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ clone.defaultRemoteName::
66
clone.rejectShallow::
77
Reject to clone a repository if it is a shallow one, can be overridden by
88
passing option `--reject-shallow` in command line. See linkgit:git-clone[1]
9+
10+
clone.filterSubmodules::
11+
If a partial clone filter is provided (see `--filter` in
12+
linkgit:git-rev-list[1]) and `--recurse-submodules` is used, also apply
13+
the filter to submodules.

Documentation/git-clone.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ SYNOPSIS
1616
[--depth <depth>] [--[no-]single-branch] [--no-tags]
1717
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
1818
[--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
19-
[--filter=<filter>] [--] <repository>
19+
[--filter=<filter> [--also-filter-submodules]] [--] <repository>
2020
[<directory>]
2121

2222
DESCRIPTION
@@ -182,6 +182,11 @@ objects from the source repository into a pack in the cloned repository.
182182
at least `<size>`. For more details on filter specifications, see
183183
the `--filter` option in linkgit:git-rev-list[1].
184184

185+
--also-filter-submodules::
186+
Also apply the partial clone filter to any submodules in the repository.
187+
Requires `--filter` and `--recurse-submodules`. This can be turned on by
188+
default by setting the `clone.filterSubmodules` config option.
189+
185190
--mirror::
186191
Set up a mirror of the source repository. This implies `--bare`.
187192
Compared to `--bare`, `--mirror` not only maps local branches of the

Documentation/git-submodule.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ If you really want to remove a submodule from the repository and commit
133133
that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal
134134
options.
135135

136-
update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--] [<path>...]::
136+
update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter spec>] [--] [<path>...]::
137137
+
138138
--
139139
Update the registered submodules to match what the superproject
@@ -177,6 +177,10 @@ submodule with the `--init` option.
177177

178178
If `--recursive` is specified, this command will recurse into the
179179
registered submodules, and update any nested submodules within.
180+
181+
If `--filter <filter spec>` is specified, the given partial clone filter will be
182+
applied to the submodule. See linkgit:git-rev-list[1] for details on filter
183+
specifications.
180184
--
181185
set-branch (-b|--branch) <branch> [--] <path>::
182186
set-branch (-d|--default) [--] <path>::

builtin/clone.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ static int option_dissociate;
7272
static int max_jobs = -1;
7373
static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
7474
static struct list_objects_filter_options filter_options;
75+
static int option_filter_submodules = -1; /* unspecified */
76+
static int config_filter_submodules = -1; /* unspecified */
7577
static struct string_list server_options = STRING_LIST_INIT_NODUP;
7678
static int option_remote_submodules;
7779

@@ -151,6 +153,8 @@ static struct option builtin_clone_options[] = {
151153
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
152154
TRANSPORT_FAMILY_IPV6),
153155
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
156+
OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
157+
N_("apply partial clone filters to submodules")),
154158
OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
155159
N_("any cloned submodules will use their remote-tracking branch")),
156160
OPT_BOOL(0, "sparse", &option_sparse_checkout,
@@ -651,7 +655,7 @@ static int git_sparse_checkout_init(const char *repo)
651655
return result;
652656
}
653657

654-
static int checkout(int submodule_progress)
658+
static int checkout(int submodule_progress, int filter_submodules)
655659
{
656660
struct object_id oid;
657661
char *head;
@@ -730,6 +734,10 @@ static int checkout(int submodule_progress)
730734
strvec_push(&args, "--no-fetch");
731735
}
732736

737+
if (filter_submodules && filter_options.choice)
738+
strvec_pushf(&args, "--filter=%s",
739+
expand_list_objects_filter_spec(&filter_options));
740+
733741
if (option_single_branch >= 0)
734742
strvec_push(&args, option_single_branch ?
735743
"--single-branch" :
@@ -750,6 +758,8 @@ static int git_clone_config(const char *k, const char *v, void *cb)
750758
}
751759
if (!strcmp(k, "clone.rejectshallow"))
752760
config_reject_shallow = git_config_bool(k, v);
761+
if (!strcmp(k, "clone.filtersubmodules"))
762+
config_filter_submodules = git_config_bool(k, v);
753763

754764
return git_default_config(k, v, cb);
755765
}
@@ -872,6 +882,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
872882
struct remote *remote;
873883
int err = 0, complete_refs_before_fetch = 1;
874884
int submodule_progress;
885+
int filter_submodules = 0;
875886

876887
struct transport_ls_refs_options transport_ls_refs_options =
877888
TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -1067,6 +1078,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
10671078
if (option_reject_shallow != -1)
10681079
reject_shallow = option_reject_shallow;
10691080

1081+
/*
1082+
* If option_filter_submodules is specified from CLI option,
1083+
* ignore config_filter_submodules from git_clone_config.
1084+
*/
1085+
if (config_filter_submodules != -1)
1086+
filter_submodules = config_filter_submodules;
1087+
if (option_filter_submodules != -1)
1088+
filter_submodules = option_filter_submodules;
1089+
1090+
/*
1091+
* Exit if the user seems to be doing something silly with submodule
1092+
* filter flags (but not with filter configs, as those should be
1093+
* set-and-forget).
1094+
*/
1095+
if (option_filter_submodules > 0 && !filter_options.choice)
1096+
die(_("the option '%s' requires '%s'"),
1097+
"--also-filter-submodules", "--filter");
1098+
if (option_filter_submodules > 0 && !option_recurse_submodules.nr)
1099+
die(_("the option '%s' requires '%s'"),
1100+
"--also-filter-submodules", "--recurse-submodules");
1101+
10701102
/*
10711103
* apply the remote name provided by --origin only after this second
10721104
* call to git_config, to ensure it overrides all config-based values.
@@ -1300,7 +1332,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13001332
}
13011333

13021334
junk_mode = JUNK_LEAVE_REPO;
1303-
err = checkout(submodule_progress);
1335+
err = checkout(submodule_progress, filter_submodules);
13041336

13051337
free(remote_name);
13061338
strbuf_release(&reflog_msg);

builtin/submodule--helper.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "object-store.h"
2222
#include "advice.h"
2323
#include "branch.h"
24+
#include "list-objects-filter-options.h"
2425

2526
#define OPT_QUIET (1 << 0)
2627
#define OPT_CACHED (1 << 1)
@@ -1631,6 +1632,7 @@ struct module_clone_data {
16311632
const char *name;
16321633
const char *url;
16331634
const char *depth;
1635+
struct list_objects_filter_options *filter_options;
16341636
struct string_list reference;
16351637
unsigned int quiet: 1;
16361638
unsigned int progress: 1;
@@ -1797,6 +1799,10 @@ static int clone_submodule(struct module_clone_data *clone_data)
17971799
strvec_push(&cp.args, "--dissociate");
17981800
if (sm_gitdir && *sm_gitdir)
17991801
strvec_pushl(&cp.args, "--separate-git-dir", sm_gitdir, NULL);
1802+
if (clone_data->filter_options && clone_data->filter_options->choice)
1803+
strvec_pushf(&cp.args, "--filter=%s",
1804+
expand_list_objects_filter_spec(
1805+
clone_data->filter_options));
18001806
if (clone_data->single_branch >= 0)
18011807
strvec_push(&cp.args, clone_data->single_branch ?
18021808
"--single-branch" :
@@ -1853,6 +1859,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
18531859
{
18541860
int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
18551861
struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
1862+
struct list_objects_filter_options filter_options;
18561863

18571864
struct option module_clone_options[] = {
18581865
OPT_STRING(0, "prefix", &clone_data.prefix,
@@ -1882,30 +1889,34 @@ static int module_clone(int argc, const char **argv, const char *prefix)
18821889
N_("disallow cloning into non-empty directory")),
18831890
OPT_BOOL(0, "single-branch", &clone_data.single_branch,
18841891
N_("clone only one branch, HEAD or --branch")),
1892+
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
18851893
OPT_END()
18861894
};
18871895

18881896
const char *const git_submodule_helper_usage[] = {
18891897
N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
18901898
"[--reference <repository>] [--name <name>] [--depth <depth>] "
1891-
"[--single-branch] "
1899+
"[--single-branch] [--filter <filter-spec>]"
18921900
"--url <url> --path <path>"),
18931901
NULL
18941902
};
18951903

1904+
memset(&filter_options, 0, sizeof(filter_options));
18961905
argc = parse_options(argc, argv, prefix, module_clone_options,
18971906
git_submodule_helper_usage, 0);
18981907

18991908
clone_data.dissociate = !!dissociate;
19001909
clone_data.quiet = !!quiet;
19011910
clone_data.progress = !!progress;
19021911
clone_data.require_init = !!require_init;
1912+
clone_data.filter_options = &filter_options;
19031913

19041914
if (argc || !clone_data.url || !clone_data.path || !*(clone_data.path))
19051915
usage_with_options(git_submodule_helper_usage,
19061916
module_clone_options);
19071917

19081918
clone_submodule(&clone_data);
1919+
list_objects_filter_release(&filter_options);
19091920
return 0;
19101921
}
19111922

@@ -1995,6 +2006,7 @@ struct submodule_update_clone {
19952006
const char *recursive_prefix;
19962007
const char *prefix;
19972008
int single_branch;
2009+
struct list_objects_filter_options *filter_options;
19982010

19992011
/* to be consumed by git-submodule.sh */
20002012
struct update_clone_data *update_clone;
@@ -2155,6 +2167,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
21552167
strvec_pushl(&child->args, "--prefix", suc->prefix, NULL);
21562168
if (suc->recommend_shallow && sub->recommend_shallow == 1)
21572169
strvec_push(&child->args, "--depth=1");
2170+
if (suc->filter_options && suc->filter_options->choice)
2171+
strvec_pushf(&child->args, "--filter=%s",
2172+
expand_list_objects_filter_spec(suc->filter_options));
21582173
if (suc->require_init)
21592174
strvec_push(&child->args, "--require-init");
21602175
strvec_pushl(&child->args, "--path", sub->path, NULL);
@@ -2499,6 +2514,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
24992514
const char *update = NULL;
25002515
struct pathspec pathspec;
25012516
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
2517+
struct list_objects_filter_options filter_options;
2518+
int ret;
25022519

25032520
struct option module_update_clone_options[] = {
25042521
OPT_STRING(0, "prefix", &prefix,
@@ -2529,6 +2546,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
25292546
N_("disallow cloning into non-empty directory")),
25302547
OPT_BOOL(0, "single-branch", &suc.single_branch,
25312548
N_("clone only one branch, HEAD or --branch")),
2549+
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
25322550
OPT_END()
25332551
};
25342552

@@ -2541,20 +2559,26 @@ static int update_clone(int argc, const char **argv, const char *prefix)
25412559
update_clone_config_from_gitmodules(&suc.max_jobs);
25422560
git_config(git_update_clone_config, &suc.max_jobs);
25432561

2562+
memset(&filter_options, 0, sizeof(filter_options));
25442563
argc = parse_options(argc, argv, prefix, module_update_clone_options,
25452564
git_submodule_helper_usage, 0);
2565+
suc.filter_options = &filter_options;
25462566

25472567
if (update)
25482568
if (parse_submodule_update_strategy(update, &suc.update) < 0)
25492569
die(_("bad value for update parameter"));
25502570

2551-
if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
2571+
if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0) {
2572+
list_objects_filter_release(&filter_options);
25522573
return 1;
2574+
}
25532575

25542576
if (pathspec.nr)
25552577
suc.warn_if_uninitialized = 1;
25562578

2557-
return update_submodules(&suc);
2579+
ret = update_submodules(&suc);
2580+
list_objects_filter_release(&filter_options);
2581+
return ret;
25582582
}
25592583

25602584
static int run_update_procedure(int argc, const char **argv, const char *prefix)

git-submodule.sh

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ USAGE="[--quiet] [--cached]
1010
or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
1111
or: $dashless [--quiet] init [--] [<path>...]
1212
or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)
13-
or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] [--] [<path>...]
13+
or: $dashless [--quiet] update [--init [--filter=<filter-spec>]] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] [--] [<path>...]
1414
or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>
1515
or: $dashless [--quiet] set-url [--] <path> <newurl>
1616
or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
@@ -49,6 +49,7 @@ dissociate=
4949
single_branch=
5050
jobs=
5151
recommend_shallow=
52+
filter=
5253

5354
die_if_unmatched ()
5455
{
@@ -347,6 +348,14 @@ cmd_update()
347348
--no-single-branch)
348349
single_branch="--no-single-branch"
349350
;;
351+
--filter)
352+
case "$2" in '') usage ;; esac
353+
filter="--filter=$2"
354+
shift
355+
;;
356+
--filter=*)
357+
filter="$1"
358+
;;
350359
--)
351360
shift
352361
break
@@ -361,6 +370,11 @@ cmd_update()
361370
shift
362371
done
363372

373+
if test -n "$filter" && test "$init" != "1"
374+
then
375+
usage
376+
fi
377+
364378
if test -n "$init"
365379
then
366380
cmd_init "--" "$@" || return
@@ -379,6 +393,7 @@ cmd_update()
379393
$single_branch \
380394
$recommend_shallow \
381395
$jobs \
396+
$filter \
382397
-- \
383398
"$@" || echo "#unmatched" $?
384399
} | {

t/t5617-clone-submodules-remote.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ test_expect_success 'setup' '
2828
)
2929
'
3030

31+
# bare clone giving "srv.bare" for use as our server.
32+
test_expect_success 'setup bare clone for server' '
33+
git clone --bare "file://$(pwd)/." srv.bare &&
34+
git -C srv.bare config --local uploadpack.allowfilter 1 &&
35+
git -C srv.bare config --local uploadpack.allowanysha1inwant 1
36+
'
37+
3138
test_expect_success 'clone with --no-remote-submodules' '
3239
test_when_finished "rm -rf super_clone" &&
3340
git clone --recurse-submodules --no-remote-submodules "file://$pwd/." super_clone &&
@@ -65,4 +72,38 @@ test_expect_success 'clone with --single-branch' '
6572
)
6673
'
6774

75+
# do basic partial clone from "srv.bare"
76+
# confirm partial clone was registered in the local config for super and sub.
77+
test_expect_success 'clone with --filter' '
78+
git clone --recurse-submodules \
79+
--filter blob:none --also-filter-submodules \
80+
"file://$pwd/srv.bare" super_clone &&
81+
test_cmp_config -C super_clone true remote.origin.promisor &&
82+
test_cmp_config -C super_clone blob:none remote.origin.partialclonefilter &&
83+
test_cmp_config -C super_clone/sub true remote.origin.promisor &&
84+
test_cmp_config -C super_clone/sub blob:none remote.origin.partialclonefilter
85+
'
86+
87+
# check that clone.filterSubmodules works (--also-filter-submodules can be
88+
# omitted)
89+
test_expect_success 'filters applied with clone.filterSubmodules' '
90+
test_config_global clone.filterSubmodules true &&
91+
git clone --recurse-submodules --filter blob:none \
92+
"file://$pwd/srv.bare" super_clone2 &&
93+
test_cmp_config -C super_clone2 true remote.origin.promisor &&
94+
test_cmp_config -C super_clone2 blob:none remote.origin.partialclonefilter &&
95+
test_cmp_config -C super_clone2/sub true remote.origin.promisor &&
96+
test_cmp_config -C super_clone2/sub blob:none remote.origin.partialclonefilter
97+
'
98+
99+
test_expect_success '--no-also-filter-submodules overrides clone.filterSubmodules=true' '
100+
test_config_global clone.filterSubmodules true &&
101+
git clone --recurse-submodules --filter blob:none \
102+
--no-also-filter-submodules \
103+
"file://$pwd/srv.bare" super_clone3 &&
104+
test_cmp_config -C super_clone3 true remote.origin.promisor &&
105+
test_cmp_config -C super_clone3 blob:none remote.origin.partialclonefilter &&
106+
test_cmp_config -C super_clone3/sub false --default false remote.origin.promisor
107+
'
108+
68109
test_done

0 commit comments

Comments
 (0)