Skip to content

Commit 22eee7f

Browse files
committed
Merge branch 'll/clone-reject-shallow'
"git clone --reject-shallow" option fails the clone as soon as we notice that we are cloning from a shallow repository. * ll/clone-reject-shallow: builtin/clone.c: add --reject-shallow option
2 parents e6b971f + 4fe788b commit 22eee7f

File tree

10 files changed

+108
-6
lines changed

10 files changed

+108
-6
lines changed

Documentation/config/clone.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@ clone.defaultRemoteName::
22
The name of the remote to create when cloning a repository. Defaults to
33
`origin`, and can be overridden by passing the `--origin` command-line
44
option to linkgit:git-clone[1].
5+
6+
clone.rejectShallow::
7+
Reject to clone a repository if it is a shallow one, can be overridden by
8+
passing option `--reject-shallow` in command line. See linkgit:git-clone[1]

Documentation/git-clone.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ SYNOPSIS
1515
[--dissociate] [--separate-git-dir <git dir>]
1616
[--depth <depth>] [--[no-]single-branch] [--no-tags]
1717
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
18-
[--[no-]remote-submodules] [--jobs <n>] [--sparse]
18+
[--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
1919
[--filter=<filter>] [--] <repository>
2020
[<directory>]
2121

@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository.
149149
--no-checkout::
150150
No checkout of HEAD is performed after the clone is complete.
151151

152+
--[no-]reject-shallow::
153+
Fail if the source repository is a shallow repository.
154+
The 'clone.rejectShallow' configuration variable can be used to
155+
specify the default.
156+
152157
--bare::
153158
Make a 'bare' Git repository. That is, instead of
154159
creating `<directory>` and placing the administrative

builtin/clone.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branch
5050
static int option_local = -1, option_no_hardlinks, option_shared;
5151
static int option_no_tags;
5252
static int option_shallow_submodules;
53+
static int option_reject_shallow = -1; /* unspecified */
54+
static int config_reject_shallow = -1; /* unspecified */
5355
static int deepen;
5456
static char *option_template, *option_depth, *option_since;
5557
static char *option_origin = NULL;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {
9092
OPT__VERBOSITY(&option_verbosity),
9193
OPT_BOOL(0, "progress", &option_progress,
9294
N_("force progress reporting")),
95+
OPT_BOOL(0, "reject-shallow", &option_reject_shallow,
96+
N_("don't clone shallow repository")),
9397
OPT_BOOL('n', "no-checkout", &option_no_checkout,
9498
N_("don't create a checkout")),
9599
OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ -858,6 +862,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)
858862
free(remote_name);
859863
remote_name = xstrdup(v);
860864
}
865+
if (!strcmp(k, "clone.rejectshallow"))
866+
config_reject_shallow = git_config_bool(k, v);
867+
861868
return git_default_config(k, v, cb);
862869
}
863870

@@ -963,6 +970,7 @@ static int path_exists(const char *path)
963970
int cmd_clone(int argc, const char **argv, const char *prefix)
964971
{
965972
int is_bundle = 0, is_local;
973+
int reject_shallow = 0;
966974
const char *repo_name, *repo, *work_tree, *git_dir;
967975
char *path = NULL, *dir, *display_repo = NULL;
968976
int dest_exists, real_dest_exists = 0;
@@ -1157,6 +1165,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11571165
*/
11581166
git_config(git_clone_config, NULL);
11591167

1168+
/*
1169+
* If option_reject_shallow is specified from CLI option,
1170+
* ignore config_reject_shallow from git_clone_config.
1171+
*/
1172+
if (config_reject_shallow != -1)
1173+
reject_shallow = config_reject_shallow;
1174+
if (option_reject_shallow != -1)
1175+
reject_shallow = option_reject_shallow;
1176+
11601177
/*
11611178
* apply the remote name provided by --origin only after this second
11621179
* call to git_config, to ensure it overrides all config-based values.
@@ -1217,6 +1234,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12171234
if (filter_options.choice)
12181235
warning(_("--filter is ignored in local clones; use file:// instead."));
12191236
if (!access(mkpath("%s/shallow", path), F_OK)) {
1237+
if (reject_shallow)
1238+
die(_("source repository is shallow, reject to clone."));
12201239
if (option_local > 0)
12211240
warning(_("source repository is shallow, ignoring --local"));
12221241
is_local = 0;
@@ -1228,6 +1247,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12281247

12291248
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
12301249

1250+
if (reject_shallow)
1251+
transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
12311252
if (option_depth)
12321253
transport_set_option(transport, TRANS_OPT_DEPTH,
12331254
option_depth);

fetch-pack.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,9 +1113,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
11131113
if (args->deepen)
11141114
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
11151115
NULL);
1116-
else if (si->nr_ours || si->nr_theirs)
1116+
else if (si->nr_ours || si->nr_theirs) {
1117+
if (args->reject_shallow_remote)
1118+
die(_("source repository is shallow, reject to clone."));
11171119
alternate_shallow_file = setup_temporary_shallow(si->shallow);
1118-
else
1120+
} else
11191121
alternate_shallow_file = NULL;
11201122
if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
11211123
&fsck_options.gitmodules_found))
@@ -1483,10 +1485,12 @@ static void receive_shallow_info(struct fetch_pack_args *args,
14831485
* rejected (unless --update-shallow is set); do the same.
14841486
*/
14851487
prepare_shallow_info(si, shallows);
1486-
if (si->nr_ours || si->nr_theirs)
1488+
if (si->nr_ours || si->nr_theirs) {
1489+
if (args->reject_shallow_remote)
1490+
die(_("source repository is shallow, reject to clone."));
14871491
alternate_shallow_file =
14881492
setup_temporary_shallow(si->shallow);
1489-
else
1493+
} else
14901494
alternate_shallow_file = NULL;
14911495
} else {
14921496
alternate_shallow_file = NULL;

fetch-pack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct fetch_pack_args {
3939
unsigned self_contained_and_connected:1;
4040
unsigned cloning:1;
4141
unsigned update_shallow:1;
42+
unsigned reject_shallow_remote:1;
4243
unsigned deepen:1;
4344

4445
/*

t/t5601-clone.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,15 @@ test_expect_success 'partial clone using HTTP' '
759759
partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
760760
'
761761

762+
test_expect_success 'reject cloning shallow repository using HTTP' '
763+
test_when_finished "rm -rf repo" &&
764+
git clone --bare --no-local --depth=1 src "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
765+
test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git repo 2>err &&
766+
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
767+
768+
git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
769+
'
770+
762771
# DO NOT add non-httpd-specific tests here, because the last part of this
763772
# test script is only executed when httpd is available and enabled.
764773

t/t5606-clone-options.sh

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ test_expect_success 'setup' '
1111
mkdir parent &&
1212
(cd parent && git init &&
1313
echo one >file && git add file &&
14-
git commit -m one)
14+
git commit -m one) &&
15+
git clone --depth=1 --no-local parent shallow-repo
1516
1617
'
1718

@@ -45,6 +46,30 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
4546
4647
'
4748

49+
test_expect_success 'reject cloning shallow repository' '
50+
test_when_finished "rm -rf repo" &&
51+
test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
52+
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
53+
54+
git clone --no-reject-shallow shallow-repo repo
55+
'
56+
57+
test_expect_success 'reject cloning non-local shallow repository' '
58+
test_when_finished "rm -rf repo" &&
59+
test_must_fail git clone --reject-shallow --no-local shallow-repo out 2>err &&
60+
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
61+
62+
git clone --no-reject-shallow --no-local shallow-repo repo
63+
'
64+
65+
test_expect_success 'succeed cloning normal repository' '
66+
test_when_finished "rm -rf chilad1 child2 child3 child4 " &&
67+
git clone --reject-shallow parent child1 &&
68+
git clone --reject-shallow --no-local parent child2 &&
69+
git clone --no-reject-shallow parent child3 &&
70+
git clone --no-reject-shallow --no-local parent child4
71+
'
72+
4873
test_expect_success 'uses "origin" for default remote name' '
4974
5075
git clone parent clone-default-origin &&

t/t5611-clone-config.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,31 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
9595
test_cmp expect actual
9696
'
9797

98+
test_expect_success 'set up shallow repository' '
99+
git clone --depth=1 --no-local . shallow-repo
100+
'
101+
102+
test_expect_success 'clone.rejectshallow=true should reject cloning shallow repo' '
103+
test_when_finished "rm -rf out" &&
104+
test_must_fail git -c clone.rejectshallow=true clone --no-local shallow-repo out 2>err &&
105+
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
106+
107+
git -c clone.rejectshallow=false clone --no-local shallow-repo out
108+
'
109+
110+
test_expect_success 'option --[no-]reject-shallow override clone.rejectshallow config' '
111+
test_when_finished "rm -rf out" &&
112+
test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local shallow-repo out 2>err &&
113+
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
114+
115+
git -c clone.rejectshallow=true clone --no-reject-shallow --no-local shallow-repo out
116+
'
117+
118+
test_expect_success 'clone.rejectshallow=true should succeed cloning normal repo' '
119+
test_when_finished "rm -rf out" &&
120+
git -c clone.rejectshallow=true clone --no-local . out
121+
'
122+
98123
test_expect_success MINGW 'clone -c core.hideDotFiles' '
99124
test_commit attributes .gitattributes "" &&
100125
rm -rf child &&

transport.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,
236236
list_objects_filter_die_if_populated(&opts->filter_options);
237237
parse_list_objects_filter(&opts->filter_options, value);
238238
return 0;
239+
} else if (!strcmp(name, TRANS_OPT_REJECT_SHALLOW)) {
240+
opts->reject_shallow = !!value;
241+
return 0;
239242
}
240243
return 1;
241244
}
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport,
370373
args.stateless_rpc = transport->stateless_rpc;
371374
args.server_options = transport->server_options;
372375
args.negotiation_tips = data->options.negotiation_tips;
376+
args.reject_shallow_remote = transport->smart_options->reject_shallow;
373377

374378
if (!data->got_remote_heads) {
375379
int i;

transport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct git_transport_options {
1414
unsigned check_self_contained_and_connected : 1;
1515
unsigned self_contained_and_connected : 1;
1616
unsigned update_shallow : 1;
17+
unsigned reject_shallow : 1;
1718
unsigned deepen_relative : 1;
1819

1920
/* see documentation of corresponding flag in fetch-pack.h */
@@ -194,6 +195,9 @@ void transport_check_allowed(const char *type);
194195
/* Aggressively fetch annotated tags if possible */
195196
#define TRANS_OPT_FOLLOWTAGS "followtags"
196197

198+
/* Reject shallow repo transport */
199+
#define TRANS_OPT_REJECT_SHALLOW "rejectshallow"
200+
197201
/* Accept refs that may update .git/shallow without --depth */
198202
#define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
199203

0 commit comments

Comments
 (0)