зеркало из https://github.com/microsoft/git.git
builtin/clone.c: add --reject-shallow option
In some scenarios, users may want more history than the repository offered for cloning, which happens to be a shallow repository, can give them. But because users don't know it is a shallow repository until they download it to local, we may want to refuse to clone this kind of repository, without creating any unnecessary files. The '--depth=x' option cannot be used as a solution; the source may be deep enough to give us 'x' commits when cloned, but the user may later need to deepen the history to arbitrary depth. Teach '--reject-shallow' option to "git clone" to abort as soon as we find out that we are cloning from a shallow repository. Signed-off-by: Li Linchao <lilinchao@oschina.cn> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
84d06cdc06
Коммит
4fe788b1b0
|
@ -2,3 +2,7 @@ clone.defaultRemoteName::
|
||||||
The name of the remote to create when cloning a repository. Defaults to
|
The name of the remote to create when cloning a repository. Defaults to
|
||||||
`origin`, and can be overridden by passing the `--origin` command-line
|
`origin`, and can be overridden by passing the `--origin` command-line
|
||||||
option to linkgit:git-clone[1].
|
option to linkgit:git-clone[1].
|
||||||
|
|
||||||
|
clone.rejectShallow::
|
||||||
|
Reject to clone a repository if it is a shallow one, can be overridden by
|
||||||
|
passing option `--reject-shallow` in command line. See linkgit:git-clone[1]
|
||||||
|
|
|
@ -15,7 +15,7 @@ SYNOPSIS
|
||||||
[--dissociate] [--separate-git-dir <git dir>]
|
[--dissociate] [--separate-git-dir <git dir>]
|
||||||
[--depth <depth>] [--[no-]single-branch] [--no-tags]
|
[--depth <depth>] [--[no-]single-branch] [--no-tags]
|
||||||
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
|
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
|
||||||
[--[no-]remote-submodules] [--jobs <n>] [--sparse]
|
[--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
|
||||||
[--filter=<filter>] [--] <repository>
|
[--filter=<filter>] [--] <repository>
|
||||||
[<directory>]
|
[<directory>]
|
||||||
|
|
||||||
|
@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository.
|
||||||
--no-checkout::
|
--no-checkout::
|
||||||
No checkout of HEAD is performed after the clone is complete.
|
No checkout of HEAD is performed after the clone is complete.
|
||||||
|
|
||||||
|
--[no-]reject-shallow::
|
||||||
|
Fail if the source repository is a shallow repository.
|
||||||
|
The 'clone.rejectShallow' configuration variable can be used to
|
||||||
|
specify the default.
|
||||||
|
|
||||||
--bare::
|
--bare::
|
||||||
Make a 'bare' Git repository. That is, instead of
|
Make a 'bare' Git repository. That is, instead of
|
||||||
creating `<directory>` and placing the administrative
|
creating `<directory>` and placing the administrative
|
||||||
|
|
|
@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branch
|
||||||
static int option_local = -1, option_no_hardlinks, option_shared;
|
static int option_local = -1, option_no_hardlinks, option_shared;
|
||||||
static int option_no_tags;
|
static int option_no_tags;
|
||||||
static int option_shallow_submodules;
|
static int option_shallow_submodules;
|
||||||
|
static int option_reject_shallow = -1; /* unspecified */
|
||||||
|
static int config_reject_shallow = -1; /* unspecified */
|
||||||
static int deepen;
|
static int deepen;
|
||||||
static char *option_template, *option_depth, *option_since;
|
static char *option_template, *option_depth, *option_since;
|
||||||
static char *option_origin = NULL;
|
static char *option_origin = NULL;
|
||||||
|
@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {
|
||||||
OPT__VERBOSITY(&option_verbosity),
|
OPT__VERBOSITY(&option_verbosity),
|
||||||
OPT_BOOL(0, "progress", &option_progress,
|
OPT_BOOL(0, "progress", &option_progress,
|
||||||
N_("force progress reporting")),
|
N_("force progress reporting")),
|
||||||
|
OPT_BOOL(0, "reject-shallow", &option_reject_shallow,
|
||||||
|
N_("don't clone shallow repository")),
|
||||||
OPT_BOOL('n', "no-checkout", &option_no_checkout,
|
OPT_BOOL('n', "no-checkout", &option_no_checkout,
|
||||||
N_("don't create a checkout")),
|
N_("don't create a checkout")),
|
||||||
OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
|
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)
|
||||||
free(remote_name);
|
free(remote_name);
|
||||||
remote_name = xstrdup(v);
|
remote_name = xstrdup(v);
|
||||||
}
|
}
|
||||||
|
if (!strcmp(k, "clone.rejectshallow"))
|
||||||
|
config_reject_shallow = git_config_bool(k, v);
|
||||||
|
|
||||||
return git_default_config(k, v, cb);
|
return git_default_config(k, v, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,6 +970,7 @@ static int path_exists(const char *path)
|
||||||
int cmd_clone(int argc, const char **argv, const char *prefix)
|
int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int is_bundle = 0, is_local;
|
int is_bundle = 0, is_local;
|
||||||
|
int reject_shallow = 0;
|
||||||
const char *repo_name, *repo, *work_tree, *git_dir;
|
const char *repo_name, *repo, *work_tree, *git_dir;
|
||||||
char *path, *dir, *display_repo = NULL;
|
char *path, *dir, *display_repo = NULL;
|
||||||
int dest_exists, real_dest_exists = 0;
|
int dest_exists, real_dest_exists = 0;
|
||||||
|
@ -1156,6 +1164,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
*/
|
*/
|
||||||
git_config(git_clone_config, NULL);
|
git_config(git_clone_config, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If option_reject_shallow is specified from CLI option,
|
||||||
|
* ignore config_reject_shallow from git_clone_config.
|
||||||
|
*/
|
||||||
|
if (config_reject_shallow != -1)
|
||||||
|
reject_shallow = config_reject_shallow;
|
||||||
|
if (option_reject_shallow != -1)
|
||||||
|
reject_shallow = option_reject_shallow;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* apply the remote name provided by --origin only after this second
|
* apply the remote name provided by --origin only after this second
|
||||||
* call to git_config, to ensure it overrides all config-based values.
|
* call to git_config, to ensure it overrides all config-based values.
|
||||||
|
@ -1216,6 +1233,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
if (filter_options.choice)
|
if (filter_options.choice)
|
||||||
warning(_("--filter is ignored in local clones; use file:// instead."));
|
warning(_("--filter is ignored in local clones; use file:// instead."));
|
||||||
if (!access(mkpath("%s/shallow", path), F_OK)) {
|
if (!access(mkpath("%s/shallow", path), F_OK)) {
|
||||||
|
if (reject_shallow)
|
||||||
|
die(_("source repository is shallow, reject to clone."));
|
||||||
if (option_local > 0)
|
if (option_local > 0)
|
||||||
warning(_("source repository is shallow, ignoring --local"));
|
warning(_("source repository is shallow, ignoring --local"));
|
||||||
is_local = 0;
|
is_local = 0;
|
||||||
|
@ -1227,6 +1246,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
|
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
|
||||||
|
|
||||||
|
if (reject_shallow)
|
||||||
|
transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
|
||||||
if (option_depth)
|
if (option_depth)
|
||||||
transport_set_option(transport, TRANS_OPT_DEPTH,
|
transport_set_option(transport, TRANS_OPT_DEPTH,
|
||||||
option_depth);
|
option_depth);
|
||||||
|
|
12
fetch-pack.c
12
fetch-pack.c
|
@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
||||||
if (args->deepen)
|
if (args->deepen)
|
||||||
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
|
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
|
||||||
NULL);
|
NULL);
|
||||||
else if (si->nr_ours || si->nr_theirs)
|
else if (si->nr_ours || si->nr_theirs) {
|
||||||
|
if (args->reject_shallow_remote)
|
||||||
|
die(_("source repository is shallow, reject to clone."));
|
||||||
alternate_shallow_file = setup_temporary_shallow(si->shallow);
|
alternate_shallow_file = setup_temporary_shallow(si->shallow);
|
||||||
else
|
} else
|
||||||
alternate_shallow_file = NULL;
|
alternate_shallow_file = NULL;
|
||||||
if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
|
if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
|
||||||
&gitmodules_oids))
|
&gitmodules_oids))
|
||||||
|
@ -1498,10 +1500,12 @@ static void receive_shallow_info(struct fetch_pack_args *args,
|
||||||
* rejected (unless --update-shallow is set); do the same.
|
* rejected (unless --update-shallow is set); do the same.
|
||||||
*/
|
*/
|
||||||
prepare_shallow_info(si, shallows);
|
prepare_shallow_info(si, shallows);
|
||||||
if (si->nr_ours || si->nr_theirs)
|
if (si->nr_ours || si->nr_theirs) {
|
||||||
|
if (args->reject_shallow_remote)
|
||||||
|
die(_("source repository is shallow, reject to clone."));
|
||||||
alternate_shallow_file =
|
alternate_shallow_file =
|
||||||
setup_temporary_shallow(si->shallow);
|
setup_temporary_shallow(si->shallow);
|
||||||
else
|
} else
|
||||||
alternate_shallow_file = NULL;
|
alternate_shallow_file = NULL;
|
||||||
} else {
|
} else {
|
||||||
alternate_shallow_file = NULL;
|
alternate_shallow_file = NULL;
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct fetch_pack_args {
|
||||||
unsigned self_contained_and_connected:1;
|
unsigned self_contained_and_connected:1;
|
||||||
unsigned cloning:1;
|
unsigned cloning:1;
|
||||||
unsigned update_shallow:1;
|
unsigned update_shallow:1;
|
||||||
|
unsigned reject_shallow_remote:1;
|
||||||
unsigned deepen:1;
|
unsigned deepen:1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -759,6 +759,15 @@ test_expect_success 'partial clone using HTTP' '
|
||||||
partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
|
partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reject cloning shallow repository using HTTP' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git clone --bare --no-local --depth=1 src "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
||||||
|
test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git repo 2>err &&
|
||||||
|
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
|
||||||
|
|
||||||
|
git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
|
||||||
|
'
|
||||||
|
|
||||||
# DO NOT add non-httpd-specific tests here, because the last part of this
|
# DO NOT add non-httpd-specific tests here, because the last part of this
|
||||||
# test script is only executed when httpd is available and enabled.
|
# test script is only executed when httpd is available and enabled.
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@ test_expect_success 'setup' '
|
||||||
mkdir parent &&
|
mkdir parent &&
|
||||||
(cd parent && git init &&
|
(cd parent && git init &&
|
||||||
echo one >file && git add file &&
|
echo one >file && git add file &&
|
||||||
git commit -m one)
|
git commit -m one) &&
|
||||||
|
git clone --depth=1 --no-local parent shallow-repo
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -45,6 +46,30 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reject cloning shallow repository' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
|
||||||
|
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
|
||||||
|
|
||||||
|
git clone --no-reject-shallow shallow-repo repo
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reject cloning non-local shallow repository' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
test_must_fail git clone --reject-shallow --no-local shallow-repo out 2>err &&
|
||||||
|
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
|
||||||
|
|
||||||
|
git clone --no-reject-shallow --no-local shallow-repo repo
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'succeed cloning normal repository' '
|
||||||
|
test_when_finished "rm -rf chilad1 child2 child3 child4 " &&
|
||||||
|
git clone --reject-shallow parent child1 &&
|
||||||
|
git clone --reject-shallow --no-local parent child2 &&
|
||||||
|
git clone --no-reject-shallow parent child3 &&
|
||||||
|
git clone --no-reject-shallow --no-local parent child4
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'uses "origin" for default remote name' '
|
test_expect_success 'uses "origin" for default remote name' '
|
||||||
|
|
||||||
git clone parent clone-default-origin &&
|
git clone parent clone-default-origin &&
|
||||||
|
|
|
@ -95,6 +95,31 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'set up shallow repository' '
|
||||||
|
git clone --depth=1 --no-local . shallow-repo
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone.rejectshallow=true should reject cloning shallow repo' '
|
||||||
|
test_when_finished "rm -rf out" &&
|
||||||
|
test_must_fail git -c clone.rejectshallow=true clone --no-local shallow-repo out 2>err &&
|
||||||
|
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
|
||||||
|
|
||||||
|
git -c clone.rejectshallow=false clone --no-local shallow-repo out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'option --[no-]reject-shallow override clone.rejectshallow config' '
|
||||||
|
test_when_finished "rm -rf out" &&
|
||||||
|
test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local shallow-repo out 2>err &&
|
||||||
|
test_i18ngrep -e "source repository is shallow, reject to clone." err &&
|
||||||
|
|
||||||
|
git -c clone.rejectshallow=true clone --no-reject-shallow --no-local shallow-repo out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone.rejectshallow=true should succeed cloning normal repo' '
|
||||||
|
test_when_finished "rm -rf out" &&
|
||||||
|
git -c clone.rejectshallow=true clone --no-local . out
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success MINGW 'clone -c core.hideDotFiles' '
|
test_expect_success MINGW 'clone -c core.hideDotFiles' '
|
||||||
test_commit attributes .gitattributes "" &&
|
test_commit attributes .gitattributes "" &&
|
||||||
rm -rf child &&
|
rm -rf child &&
|
||||||
|
|
|
@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,
|
||||||
list_objects_filter_die_if_populated(&opts->filter_options);
|
list_objects_filter_die_if_populated(&opts->filter_options);
|
||||||
parse_list_objects_filter(&opts->filter_options, value);
|
parse_list_objects_filter(&opts->filter_options, value);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!strcmp(name, TRANS_OPT_REJECT_SHALLOW)) {
|
||||||
|
opts->reject_shallow = !!value;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport,
|
||||||
args.stateless_rpc = transport->stateless_rpc;
|
args.stateless_rpc = transport->stateless_rpc;
|
||||||
args.server_options = transport->server_options;
|
args.server_options = transport->server_options;
|
||||||
args.negotiation_tips = data->options.negotiation_tips;
|
args.negotiation_tips = data->options.negotiation_tips;
|
||||||
|
args.reject_shallow_remote = transport->smart_options->reject_shallow;
|
||||||
|
|
||||||
if (!data->got_remote_heads) {
|
if (!data->got_remote_heads) {
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -14,6 +14,7 @@ struct git_transport_options {
|
||||||
unsigned check_self_contained_and_connected : 1;
|
unsigned check_self_contained_and_connected : 1;
|
||||||
unsigned self_contained_and_connected : 1;
|
unsigned self_contained_and_connected : 1;
|
||||||
unsigned update_shallow : 1;
|
unsigned update_shallow : 1;
|
||||||
|
unsigned reject_shallow : 1;
|
||||||
unsigned deepen_relative : 1;
|
unsigned deepen_relative : 1;
|
||||||
|
|
||||||
/* see documentation of corresponding flag in fetch-pack.h */
|
/* see documentation of corresponding flag in fetch-pack.h */
|
||||||
|
@ -194,6 +195,9 @@ void transport_check_allowed(const char *type);
|
||||||
/* Aggressively fetch annotated tags if possible */
|
/* Aggressively fetch annotated tags if possible */
|
||||||
#define TRANS_OPT_FOLLOWTAGS "followtags"
|
#define TRANS_OPT_FOLLOWTAGS "followtags"
|
||||||
|
|
||||||
|
/* Reject shallow repo transport */
|
||||||
|
#define TRANS_OPT_REJECT_SHALLOW "rejectshallow"
|
||||||
|
|
||||||
/* Accept refs that may update .git/shallow without --depth */
|
/* Accept refs that may update .git/shallow without --depth */
|
||||||
#define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
|
#define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче