builtin/clone.c: add --no-shallow option
PATCH 1/1 builtin/clone.c: add --no-shallow option
From: lilinchao <[email protected]>
This patch add a new option that reject to clone a shallow repository. Clients don't know it's a shallow repository until they download it locally, in some scenariors, clients just don't want to clone this kind of repository, and want to exit the process immediately without creating any unnecessary files.
---
builtin/clone.c: add --no-shallow option
This patch add a new option that reject to clone a shallow repository. Clients don't know it's a shallow repository until they download it locally, in some scenariors, clients just don't want to clone this kind of repository, and want to exit the process immediately without creating any unnecessary files.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Documentation/config/clone.txt | 3 +++ Documentation/git-clone.txt | 8 +++++++- builtin/clone.c | 13 +++++++++++++ t/t5606-clone-options.sh | 7 +++++++ t/t5611-clone-config.sh | 7 +++++++ 5 files changed, 37 insertions(+), 1 deletion(-) mode change 100644 => 100755 builtin/clone.c
Documentation/config/clone.txt +3 -0
@@ -2,3 +2,6 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line option to linkgit:git-clone[1]. + +clone.rejectshallow:: + Reject to clone a repository if it is a shallow one.
Documentation/git-clone.txt +7 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--no-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -145,6 +145,12 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: No checkout of HEAD is performed after the clone is complete. +--no-shallow:: + Don't clone a shallow source repository. In some scenariors, clients + want the cloned repository information to be complete. Otherwise, + the cloning process should end immediately without creating any files, + which can save some disk space. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +13 -0
@@ -50,6 +50,7 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_no_shallow;static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +91,7 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"no-shallow" , &option_no_shallow,N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ -858,6 +860,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + option_no_shallow =1 ; + }return git_default_config (k, v, cb); }
@@ -963,6 +968,7 @@ static int path_exists(const char *path)int cmd_clone (int argc,const char **argv,const char *prefix) {int is_bundle =0 , is_local; +int is_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1215,6 +1221,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { + is_shallow =1 ;if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1222,6 +1229,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) }if (option_local >0 && !is_local)warning (_ ("--local is ignored" )); + +if (is_shallow) { +if (option_no_shallow) +die (_ ("source repository is shallow, reject to clone." )); + } + transport->cloning =1 ;transport_set_option (transport,TRANS_OPT_KEEP ,"yes" );
t/t5606-clone-options.sh +7 -0
@@ -42,6 +42,13 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' ' +test_expect_success 'reject clone shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --no-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + test_expect_success 'uses "origin" for default remote name' ' git clone parent clone-default-origin &&
t/t5611-clone-config.sh +7 -0
@@ -92,6 +92,13 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone -c clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git clone -c clone.rejectshallow child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
base-commit: 72c4083ddf91b489b7b7b812df67ee8842177d98
Signature · 1 line
gitgitgadget
Quoted 3 lines · Li Linchao via GitGitGadget
From: lilinchao <[email protected]>
This patch add a new option that reject to clone a shallow repository.
A canonical form of our log message starts by explaining the need, and then presents the solution at the end.
Quoted 2 lines
Clients don't know it's a shallow repository until they download it locally, in some scenariors, clients just don't want to clone this kind
"scenarios". "in some scenarios" would have to be clarified a bit more to justify why it is a good idea to have such a feature.
Quoted 2 lines
of repository, and want to exit the process immediately without creating any unnecessary files.
"clients don't know it's a shallow repository until they download" leading to "so let's reject immediately upon finding out that they are shallow" does make sense as a flow of thought, though.
Documentation/git-clone.txt objects from the source repository into a pack in the cloned repository. · line 149
Quoted 2 lines
+--no-shallow::
Documentation/git-clone.txt +1
-0+ Don't clone a shallow source repository. In some scenariors, clients
"scenarios" (no 'r').
builtin/clone.c
Quoted 3 lines
builtin/clone.c +0
-0
Unwarranted "chmod +x"; accidents do happen, but please be careful before making what you did public ;-)
builtin/clone.c static struct option builtin_clone_options[] = { · line 97
Quoted 8 lines
builtin/clone.c +1
-0@@ -90,6 +91,7 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"no-shallow" , &option_no_shallow,N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
It is a bad idea to give a name that begins with "no-" to an option whose default can be tweaked by a configuration variable [*]. If the configuration is named "rejectshallow", perhaps it is better to call it "--reject-shallow" instead.
This is because configured default must be overridable from the command line. I.e. even if you have in your ~/.gitconfig this:
[clone]
rejectshallow = true
you should be able to say "allow it only this time", with
$ git clone --no-reject-shallow http://github.com/git/git/ git
and you do not want to have to say "--no-no-shallow", which sounds just silly.
Side note. it is a bad idea in general, even if the option does not have corresponding configuration variable. The existing "no-checkout" is a historical accident that happened long time ago and cannot be removed due to compatibility. Let's not introduce a new option that follows such a bad pattern.
Quoted 9 lines
builtin/clone.c +1
-0@@ -963,6 +968,7 @@ static int path_exists(const char *path)int cmd_clone (int argc,const char **argv,const char *prefix) {int is_bundle =0 , is_local; +int is_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1227
Quoted 7 lines
builtin/clone.c +1
-0@@ -1215,6 +1221,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { + is_shallow =1 ;if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
This change is to the local clone codepath. Cloning over the wire would not go through this part. And throughout the patch, this is the only place that sets is_shallow to 1.
Also let's note that this is after we called parse_options(), so the value of option_no_shallow is known at this point.
So, this patch does not even *need* to introduce a new "is_shallow" variable at all. It only needs to add
if (option_no_shallow)
die(...);instead of adding "is_shallow = 1" to the above hunk.
I somehow think that this is only half a feature---wouldn't it be more useful if we also rejected a non-local clone from a shallow repository?
And for that ...
Quoted 5 lines
t/t5606-clone-options.sh +0
-0
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 51
Quoted 10 lines
t/t5606-clone-options.sh +7
-0@@ -42,6 +42,13 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' ' +test_expect_success 'reject clone shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --no-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' +
... in addition to the test for a local clone above, you'd also want to test a non-local clone, perhaps like so:
test_expect_success 'reject clone shallow repository' '
rm -fr shallow-repo && git clone --depth=1 --no-local parent shallow-repo && test_must_fail git clone --no-shallow --no-local shallow-repo out 2>err && test_i18ngrep -e "source repository is shallow, reject to clone." err
'
Ditto for the other test script.
Also, you would want to make sure that the command line overrides the configured default. I.e.
git -c clone.rejectshallow=false clone --reject-shallow
should refuse to clone from a shallow one, while there should be a way to countermand a configured "I always refuse to clone from a shallow repository" with "but let's allow it only this time", i.e.
git -c clone.rejectshallow=true clone --no-reject-shallow
or something along the line.
t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 98
Quoted 12 lines
t/t5611-clone-config.sh +4
-0@@ -92,6 +92,13 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone -c clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git clone -c clone.rejectshallow child out 2>err &&
This is not quite right, even though it may happen to work. The "clone.rejectshallow" variable is a configuration about what should happen when creating a new repository by cloning, so letting "git clone -c var[=val]" to set the variable _in_ the resulting repository would not make much sense. Even if the clone succeeded, nobody would look at that particular configuration variable that is set in the resulting repository.
I think it would communicate to the readers better what we are trying to do, if we write
test_must_fail git -c clone.rejectshallow=true clone child out
instead.
Thanks.
--------------
[email protected]
Quoted 8 lines
Quoted 3 lines · Li Linchao via GitGitGadget
From: lilinchao <[email protected]>
This patch add a new option that reject to clone a shallow repository.
A canonical form of our log message starts by explaining the need, and then presents the solution at the end.
Ok, will do.
Quoted 6 lines
Quoted 3 lines
Clients don't know it's a shallow repository until they download it locally, in some scenariors, clients just don't want to clone this kind
"scenarios". "in some scenarios" would have to be clarified a bit more to justify why it is a good idea to have such a feature.
I found an issue described like this:
The blame information can be completely wrong when fetching it from a shallow clone, without errors or warnings. When the outcome is invalid data, it's extremely difficult to diagnose that it comes from a shallow clone. If a line in a file was not changed in the commits that were downloaded as part of the shallow fetch, git will report the first known commit as the author. This has a big impact on the auto-assignment of new issues.
It looks like this is another scenario that can prove this feature is necessary.
Quoted 13 lines
Quoted 3 lines
of repository, and want to exit the process immediately without creating any unnecessary files.
"clients don't know it's a shallow repository until they download" leading to "so let's reject immediately upon finding out that they are shallow" does make sense as a flow of thought, though.
Documentation/git-clone.txt objects from the source repository into a pack in the cloned repository. · line 149
Quoted 2 lines
+--no-shallow::
Documentation/git-clone.txt +1
-0+ Don't clone a shallow source repository. In some scenariors, clients"scenarios" (no 'r').
Quoted 6 lines
builtin/clone.c
Quoted 3 lines
builtin/clone.c +0
-0Unwarranted "chmod +x"; accidents do happen, but please be careful before making what you did public ;-)
Oops, this happened when I edited it in VS Code, it noticed me 'permission denied' when I want to save the file.
Quoted 28 lines
builtin/clone.c static struct option builtin_clone_options[] = { · line 97
Quoted 9 lines
builtin/clone.c +1
-0@@ -90,6 +91,7 @@ static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), OPT_BOOL(0, "progress", &option_progress, N_("force progress reporting")), +OPT_BOOL (0 ,"no-shallow" , &option_no_shallow,N_ ("don't clone shallow repository" )), OPT_BOOL('n', "no-checkout", &option_no_checkout, N_("don't create a checkout")), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),It is a bad idea to give a name that begins with "no-" to an option whose default can be tweaked by a configuration variable [*]. If the configuration is named "rejectshallow", perhaps it is better to call it "--reject-shallow" instead.
This is because configured default must be overridable from the command line. I.e. even if you have in your ~/.gitconfig this:
[clone]
rejectshallow = trueyou should be able to say "allow it only this time", with
$ git clone --no-reject-shallow http://github.com/git/git/ gitand you do not want to have to say "--no-no-shallow", which sounds just silly.
Quoted 7 lines
Side note. it is a bad idea in general, even if the option does not have corresponding configuration variable. The existing "no-checkout" is a historical accident that happened long time ago and cannot be removed due to compatibility. Let's not introduce a new option that follows such a bad pattern.
You're right, "--reject-shallow" is much better.
I didn't realize that bool options have default [no-] option.
Quoted 30 lines
Quoted 9 lines
builtin/clone.c +1
-0@@ -963,6 +968,7 @@ static int path_exists(const char *path) int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; +int is_shallow =0 ; const char *repo_name, *repo, *work_tree, *git_dir; char *path, *dir, *display_repo = NULL; int dest_exists, real_dest_exists = 0;builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1227
Quoted 7 lines
builtin/clone.c +1
-0@@ -1215,6 +1221,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (filter_options.choice) warning(_("--filter is ignored in local clones; use file:// instead.")); if (!access(mkpath("%s/shallow", path), F_OK)) { + is_shallow =1 ; if (option_local > 0) warning(_("source repository is shallow, ignoring --local")); is_local = 0;This change is to the local clone codepath. Cloning over the wire would not go through this part. And throughout the patch, this is the only place that sets
is_shallowto 1.Also let's note that this is after we called
parse_options(), so the value ofoption_no_shallowis known at this point.So, this patch does not even *need* to introduce a new "
is_shallow" variable at all. It only needs to addif (
option_no_shallow)
die(...);
Quoted 8 lines
instead of adding "
is_shallow= 1" to the above hunk.I somehow think that this is only half a feature---wouldn't it be more useful if we also rejected a non-local clone from a shallow repository?
And for that ...
After I applied your review suggestions above, then we can reject a non-local clone from shallow repo. For now, it will clone a empty repo with --no-local option.
Quoted 65 lines
Quoted 9 lines
t/t5606-clone-options.sh +0
-0@@ -42,6 +42,13 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
't/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 51
Quoted 7 lines
t/t5606-clone-options.sh +7
-0+test_expect_success 'reject clone shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --no-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' +... in addition to the test for a local clone above, you'd also want to test a non-local clone, perhaps like so:
test_expect_success'reject clone shallow repository' 'rm -fr shallow-repo && git clone --depth=1 --no-local parent shallow-repo && test_must_fail git clone --no-shallow --no-local shallow-repo out 2>err && test_i18ngrep -e "source repository is shallow, reject to clone." err'
Ditto for the other test script.
Also, you would want to make sure that the command line overrides the configured default. I.e.
git -c clone.rejectshallow=false clone --reject-shallowshould refuse to clone from a shallow one, while there should be a way to countermand a configured "I always refuse to clone from a shallow repository" with "but let's allow it only this time", i.e.
git -c clone.rejectshallow=true clone --no-reject-shallowor something along the line.
t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 98
Quoted 12 lines
t/t5611-clone-config.sh +0
-0@@ -92,6 +92,13 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
test_cmpexpect actual
't/t5611-clone-config.sh +4
-0+test_expect_success 'clone -c clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git clone -c clone.rejectshallow child out 2>err &&This is not quite right, even though it may happen to work. The "clone.rejectshallow" variable is a configuration about what should happen when creating a new repository by cloning, so letting "git clone -c var[=val]" to set the variable _in_ the resulting repository would not make much sense. Even if the clone succeeded, nobody would look at that particular configuration variable that is set in the resulting repository.
Quoted 8 lines
I think it would communicate to the readers better what we are trying to do, if we write
test_must_failgit -c clone.rejectshallow=true clone child outinstead.
Thanks.
Thank you for so many effective suggestions, I will write test case more carefully :)
Hi,
in addition to what Junio said:
builtin/clone.c static int git_clone_config(const char *k, const char *v, void *cb) · line 864
Quoted 10 lines · Li Linchao via GitGitGadget
builtin/clone.c +2
-0@@ -858,6 +860,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + option_no_shallow =1 ;
This needs to use git_config_bool(k, v) to allow for clone.rejectShallow = false.
Ciao,
Dscho
Quoted 6 lines · Johannes Schindelin
Hi,
in addition to what Junio said:
On Thu, 4 Feb 2021, Li Linchao via GitGitGadget wrote:
Quoted 13 lines
builtin/clone.c static int git_clone_config(const char *k, const char *v, void *cb) · line 864
Quoted 10 lines
builtin/clone.c +2
-0@@ -858,6 +860,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + option_no_shallow =1 ;This needs to use
git_config_bool(k, v)to allow forclone.rejectShallow = false.
Thanks. I completely missed that.
Quoted 10 lines · "[email protected]" <[email protected]> writes:
I found an issue described like this:
The blame information can be completely wrong when fetching it from a shallow clone, without errors or warnings. When the outcome is invalid data, it's extremely difficult to diagnose that it comes from a shallow clone. If a line in a file was not changed in the commits that were downloaded as part of the shallow fetch, git will report the first known commit as the author. This has a big impact on the auto-assignment of new issues.
It looks like this is another scenario that can prove this feature is necessary.
In other words:
Users may want more history than the repository offered for cloning, which happens to be shallow, can give them.
And the way chosen by "--reject-shallow" is to require that the source repository has the entire history.
I wonder if the design of this UI is flexible enough so that we can extend it to allow "I need the history that goes back at least to X" in the future. "I need the history goes back to all the roots" then becomes a narrow special case of that.
Quoted 3 lines
After I applied your review suggestions above, then we can reject a non-local clone from shallow repo. For now, it will clone a empty repo with --no-local option.
It is my understanding that your patch with or without my suggestion only deals with local clone and does not change anything for non-local case. A "local-only" solution is a good place to start and is a good test bed to experiment with the user experience, but I view without support for non-local clone, it would not be ready for general use.
Thanks.
PATCH v2 1/2 builtin/clone.c: add --no-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
This patch add a new option that reject to clone a shallow repository. Clients don't know it's a shallow repository until they download it locally, in some scenariors, clients just don't want to clone this kind of repository, and want to exit the process immediately without creating any unnecessary files.
--- Documentation/config/clone.txt | 3 +++ Documentation/git-clone.txt | 8 +++++++- builtin/clone.c | 13 +++++++++++++ t/t5606-clone-options.sh | 7 +++++++ t/t5611-clone-config.sh | 7 +++++++ 5 files changed, 37 insertions(+), 1 deletion(-) mode change 100644 => 100755 builtin/clone.c
Documentation/config/clone.txt +3 -0
@@ -2,3 +2,6 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line option to linkgit:git-clone[1]. + +clone.rejectshallow:: + Reject to clone a repository if it is a shallow one.
Documentation/git-clone.txt +7 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--no-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,12 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: No checkout of HEAD is performed after the clone is complete. +--no-shallow:: + Don't clone a shallow source repository. In some scenariors, clients + want the cloned repository information to be complete. Otherwise, + the cloning process should end immediately without creating any files, + which can save some disk space. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +13 -0
@@ -50,6 +50,7 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_no_shallow;static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +91,7 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"no-shallow" , &option_no_shallow,N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ -858,6 +860,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + option_no_shallow =1 ; + }return git_default_config (k, v, cb); }
@@ -963,6 +968,7 @@ static int path_exists(const char *path)int cmd_clone (int argc,const char **argv,const char *prefix) {int is_bundle =0 , is_local; +int is_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1215,6 +1221,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { + is_shallow =1 ;if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1222,6 +1229,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) }if (option_local >0 && !is_local)warning (_ ("--local is ignored" )); + +if (is_shallow) { +if (option_no_shallow) +die (_ ("source repository is shallow, reject to clone." )); + } + transport->cloning =1 ;transport_set_option (transport,TRANS_OPT_KEEP ,"yes" );
t/t5606-clone-options.sh +7 -0
@@ -45,6 +45,13 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' ' +test_expect_success 'reject clone shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --no-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + test_expect_success 'uses "origin" for default remote name' ' git clone parent clone-default-origin &&
t/t5611-clone-config.sh +7 -0
@@ -95,6 +95,13 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone -c clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git clone -c clone.rejectshallow child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
Signature · 1 line
gitgitgadget
PATCH v2 2/2 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
In some scenarios, users may want more history than the repository offered for cloning, which mostly to be a shallow repository, can give them. But users don't know it is a shallow repository until they download it to local, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, given that we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import an unshallow repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
--- Documentation/config/clone.txt | 3 ++- Documentation/git-clone.txt | 20 ++++++++++++++++---- builtin/clone.c | 32 ++++++++++++++++++++++++++------ t/t5606-clone-options.sh | 33 +++++++++++++++++++++++++++++++-- t/t5611-clone-config.sh | 29 +++++++++++++++++++++++++++-- 5 files changed, 102 insertions(+), 15 deletions(-) mode change 100755 => 100644 builtin/clone.c
Documentation/config/clone.txt +2 -1
@@ -4,4 +4,5 @@ clone.defaultRemoteName:: option to linkgit:git-clone[1]. clone.rejectshallow:: - Reject to clone a repository if it is a shallow one. + 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]
Documentation/git-clone.txt +16 -4
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--no-shallow] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,11 +149,23 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: No checkout of HEAD is performed after the clone is complete. ---no-shallow:: - Don't clone a shallow source repository. In some scenariors, clients +--reject-shallow:: + Don't clone a shallow source repository. In some scenarios, clients want the cloned repository information to be complete. Otherwise, the cloning process should end immediately without creating any files, - which can save some disk space. + which can save some disk space. This can override `clone.rejectshallow` + from the configuration: + + -------------------------------------------------------------------- + $ git -c clone.rejectshallow=false clone --reject-shallow source out + -------------------------------------------------------------------- + + While there is a way to countermand a configured "I always refuse to + clone from a shallow repository" with "but let's allow it only this time": + + ---------------------------------------------------------------------- + $ git -c clone.rejectshallow=true clone --no-reject-shallow source out + ---------------------------------------------------------------------- --bare:: Make a 'bare' Git repository. That is, instead of
builtin/clone.c +26 -6
@@ -50,7 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; -static int option_no_shallow; +static int option_no_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -91,7 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), -OPT_BOOL (0 ,"no-shallow" , &option_no_shallow,N_ ("don't clone shallow repository" )), +OPT_BOOL (0 ,"reject-shallow" , &option_no_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ -861,7 +863,7 @@ static int git_clone_config(const char *k, const char *v, void *cb) remote_name =xstrdup (v); }if (!strcmp (k,"clone.rejectshallow" )) { - option_no_shallow =1 ; + config_shallow =git_config_bool (k, v); }return git_default_config (k, v, cb); }
@@ -1211,6 +1213,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path =get_repo_path (remote->url[0 ], &is_bundle); is_local = option_local !=0 && path && !is_bundle; + +/* Detect if the remote repository is shallow */ +if (!access (mkpath ("%s/shallow" , path),F_OK )) { + is_shallow =1 ; + } +if (is_local) {if (option_depth)warning (_ ("--depth is ignored in local clones; use file:// instead." ));
@@ -1220,8 +1228,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)warning (_ ("--shallow-exclude is ignored in local clones; use file:// instead." ));if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." )); -if (!access (mkpath ("%s/shallow" , path),F_OK )) { - is_shallow =1 ; +if (is_shallow) {if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1231,8 +1238,21 @@ int cmd_clone(int argc, const char **argv, const char *prefix)warning (_ ("--local is ignored" ));if (is_shallow) { -if (option_no_shallow) +int reject =0 ; + +/* If option_no_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ + +if (config_shallow !=-1 ) { + reject = config_shallow; + } +if (option_no_shallow !=-1 ) { + reject = option_no_shallow; + } +if (reject) {die (_ ("source repository is shallow, reject to clone." )); + } } transport->cloning =1 ;
t/t5606-clone-options.sh +31 -2
@@ -45,13 +45,42 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' ' -test_expect_success 'reject clone shallow repository' ' +test_expect_success 'fail to clone shallow repository' ' git clone --depth=1 --no-local parent shallow-repo && - test_must_fail git clone --no-shallow shallow-repo out 2>err && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && test_i18ngrep -e "source repository is shallow, reject to clone." err ' +test_expect_success 'fail to clone non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +' + +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repo + +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' + test_expect_success 'uses "origin" for default remote name' ' git clone parent clone-default-origin &&
t/t5611-clone-config.sh +27 -2
@@ -95,13 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' -test_expect_success 'clone -c clone.rejectshallow' ' +test_expect_success 'clone.rejectshallow=true should fail to clone' ' rm -rf child && git clone --depth=1 --no-local . child && - test_must_fail git clone -c clone.rejectshallow child out 2>err && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && test_i18ngrep -e "source repository is shallow, reject to clone." err ' +test_expect_success 'clone.rejectshallow=false should succeed cloning' ' + rm -rf child && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed cloning normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git clone -c clone.rejectshallow=false --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success ' option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
Signature · 1 line
gitgitgadget
v2 cover builtin/clone.c: add --no-shallow option
In reply to Li Linchao via GitGitGadgetChange since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
lilinchao (2):
builtin/clone.c: add --no-shallow option
builtin/clone.c: add --reject-shallow option
Documentation/config/clone.txt | 4 ++++ Documentation/git-clone.txt | 20 ++++++++++++++++++- builtin/clone.c | 35 ++++++++++++++++++++++++++++++++- t/t5606-clone-options.sh | 36 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 ++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 2 deletions(-)
base-commit: fb7fa4a1fd273f22efcafdd13c7f897814fd1eb9
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v1:
1: 594323684af0 = 1: 2f9602495eb5 builtin/clone.c: add --no-shallow option -: ------------ > 2: cfcfc3ec6b37 builtin/clone.c: add --reject-shallow option
Signature · 1 line
gitgitgadget
Quoted 4 lines · Li Linchao via GitGitGadget
Range-diff vs v1:
1: 594323684af0 = 1: 2f9602495eb5 builtin/clone.c: add --no-shallow option -: ------------ > 2: cfcfc3ec6b37 builtin/clone.c: add --reject-shallow option
You should rewrite your history to make this one commit again. You can do this by running 'git rebase -i HEAD~2' then editing the todo file to 'squash' the second commit in to the first. You will be prompted to edit the combined commit message, and you should preserve only the message from the second commit.
Thanks,
-Stolee
Thanks, have done. And I am waiting for all CI on Github to turn green.
--------------
[email protected]
Quoted 15 lines · Li Linchao via GitGitGadget
Quoted 4 lines
Range-diff vs v1:
1:
594323684af0= 1:2f9602495eb5builtin/clone.c: add --no-shallow option -: ------------ > 2:cfcfc3ec6b37builtin/clone.c: add --reject-shallow optionYou should rewrite your history to make this one commit again. You can do this by running 'git rebase -i HEAD~2' then editing the todo file to 'squash' the second commit in to the first. You will be prompted to edit the combined commit message, and you should preserve only the message from the second commit.
Thanks,
-Stolee
PATCH v3 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
In some scenarios, users may want more history than the repository offered for cloning, which mostly to be a shallow repository, can give them. But users don't know it is a shallow repository until they download it to local, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, given that we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import an unshallow repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --no-shallow option
Change since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v2:
1: 2f9602495eb5 < -: ------------ builtin/clone.c: add --no-shallow option
2: cfcfc3ec6b37 ! 1: f5ed6b2e4481 builtin/clone.c: add --reject-shallow option
@@ Commit message
## Documentation/config/clone.txt ##
@@ Documentation/config/clone.txt: clone.defaultRemoteName::
+ The name of the remote to create when cloning a repository. Defaults to
+ `origin`, and can be overridden by passing the `--origin` command-line
option to linkgit:git-clone[1].
-
- clone.rejectshallow::
-- Reject to clone a repository if it is a shallow one.
++
++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]
@@ Documentation/git-clone.txt: SYNOPSIS
[--dissociate] [--separate-git-dir <git dir>]
[--depth <depth>] [--[no-]single-branch] [--no-tags]
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
-- [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--no-shallow]
+- [--[no-]remote-submodules] [--jobs <n>] [--sparse]
+ [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--reject-shallow]
[--filter=<filter>] [--] <repository>
[<directory>]
@@ Documentation/git-clone.txt: objects from the source repository into a pack in t
--no-checkout::
No checkout of HEAD is performed after the clone is complete.
----no-shallow::
-- Don't clone a shallow source repository. In some scenariors, clients
+--reject-shallow::
+ Don't clone a shallow source repository. In some scenarios, clients
- want the cloned repository information to be complete. Otherwise,
- the cloning process should end immediately without creating any files,
-- which can save some disk space.
++ want the cloned repository information to be complete. Otherwise,
++ the cloning process should end immediately without creating any files,
+ which can save some disk space. This can override `clone.rejectshallow`
+ from the configuration:
+
@@ Documentation/git-clone.txt: objects from the source repository into a pack in t
+ ----------------------------------------------------------------------
+ $ git -c clone.rejectshallow=true clone --no-reject-shallow source out
+ ----------------------------------------------------------------------
-
++
--bare::
Make a 'bare' Git repository. That is, instead of
+ creating `<directory>` and placing the administrative
- ## builtin/clone.c (mode change 100755 => 100644) ##
+ ## builtin/clone.c ##
@@ builtin/clone.c: 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_no_tags;
static int option_shallow_submodules;
--static int option_no_shallow;
+static int option_no_shallow = -1; /* unspecified */
+static int config_shallow = -1; /* unspecified */
static int deepen;
@@ builtin/clone.c: static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
N_("force progress reporting")),
-- OPT_BOOL(0, "no-shallow", &option_no_shallow, N_("don't clone shallow repository")),
+ OPT_BOOL(0, "reject-shallow", &option_no_shallow,
+ N_("don't clone shallow repository")),
OPT_BOOL('n', "no-checkout", &option_no_checkout,
N_("don't create a checkout")),
OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ builtin/clone.c: static int git_clone_config(const char *k, const char *v, void *cb)
+ free(remote_name);
remote_name = xstrdup(v);
}
- if (!strcmp(k, "clone.rejectshallow")) {
-- option_no_shallow = 1;
++ if (!strcmp(k, "clone.rejectshallow")) {
+ config_shallow = git_config_bool(k, v);
- }
++ }
return git_default_config(k, v, cb);
}
+
+@@ builtin/clone.c: static int path_exists(const char *path)
+ int cmd_clone(int argc, const char **argv, const char *prefix)
+ {
+ int is_bundle = 0, is_local;
++ int is_shallow = 0;
+ const char *repo_name, *repo, *work_tree, *git_dir;
+ char *path, *dir, *display_repo = NULL;
+ int dest_exists, real_dest_exists = 0;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
path = get_repo_path(remote->url[0], &is_bundle);
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
if (filter_options.choice)
warning(_("--filter is ignored in local clones; use file:// instead."));
- if (!access(mkpath("%s/shallow", path), F_OK)) {
-- is_shallow = 1;
+ if (is_shallow) {
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
+ }
+ if (option_local > 0 && !is_local)
warning(_("--local is ignored"));
-
- if (is_shallow) {
-- if (option_no_shallow)
++
++ if (is_shallow) {
+ int reject = 0;
+
+ /* If option_no_shallow is specified from CLI option,
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
+ reject = option_no_shallow;
+ }
+ if (reject) {
- die(_("source repository is shallow, reject to clone."));
++ die(_("source repository is shallow, reject to clone."));
+ }
- }
-
++ }
++
transport->cloning = 1;
+
+ transport_set_option(transport, TRANS_OPT_KEEP, "yes");
## t/t5606-clone-options.sh ##
@@ t/t5606-clone-options.sh: test_expect_success 'disallows --bare with --separate-git-dir' '
'
--test_expect_success 'reject clone shallow repository' '
+test_expect_success 'fail to clone shallow repository' '
- git clone --depth=1 --no-local parent shallow-repo &&
-- test_must_fail git clone --no-shallow shallow-repo out 2>err &&
++ git clone --depth=1 --no-local parent shallow-repo &&
+ test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err
-
- '
-
++ test_i18ngrep -e "source repository is shallow, reject to clone." err
++
++'
++
+test_expect_success 'fail to clone non-local shallow repository' '
+ rm -rf shallow-repo &&
+ git clone --depth=1 --no-local parent shallow-repo &&
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
test_cmp expect actual
'
--test_expect_success 'clone -c clone.rejectshallow' '
+test_expect_success 'clone.rejectshallow=true should fail to clone' '
- rm -rf child &&
- git clone --depth=1 --no-local . child &&
-- test_must_fail git clone -c clone.rejectshallow child out 2>err &&
++ rm -rf child &&
++ git clone --depth=1 --no-local . child &&
+ test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err &&
- test_i18ngrep -e "source repository is shallow, reject to clone." err
- '
-
++ test_i18ngrep -e "source repository is shallow, reject to clone." err
++'
++
+test_expect_success 'clone.rejectshallow=false should succeed cloning' '
+ rm -rf child &&
+ git clone --depth=1 --no-local . child &&Documentation/config/clone.txt | 4 ++++ Documentation/git-clone.txt | 20 ++++++++++++++++++- builtin/clone.c | 35 ++++++++++++++++++++++++++++++++- t/t5606-clone-options.sh | 36 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 ++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 2 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +19 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,24 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: No checkout of HEAD is performed after the clone is complete. +--reject-shallow:: + Don't clone a shallow source repository. In some scenarios, clients + want the cloned repository information to be complete. Otherwise, + the cloning process should end immediately without creating any files, + which can save some disk space. This can override `clone.rejectshallow` + from the configuration: + + -------------------------------------------------------------------- + $ git -c clone.rejectshallow=false clone --reject-shallow source out + -------------------------------------------------------------------- + + While there is a way to countermand a configured "I always refuse to + clone from a shallow repository" with "but let's allow it only this time": + + ---------------------------------------------------------------------- + $ git -c clone.rejectshallow=true clone --no-reject-shallow source out + ---------------------------------------------------------------------- + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +34 -1
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_no_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_no_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + config_shallow =git_config_bool (k, v); + }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 is_bundle =0 , is_local; +int is_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1205,6 +1213,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path =get_repo_path (remote->url[0 ], &is_bundle); is_local = option_local !=0 && path && !is_bundle; + +/* Detect if the remote repository is shallow */ +if (!access (mkpath ("%s/shallow" , path),F_OK )) { + is_shallow =1 ; + } +if (is_local) {if (option_depth)warning (_ ("--depth is ignored in local clones; use file:// instead." ));
@@ -1214,7 +1228,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)warning (_ ("--shallow-exclude is ignored in local clones; use file:// instead." ));if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." )); -if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (is_shallow) {if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1222,6 +1236,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix) }if (option_local >0 && !is_local)warning (_ ("--local is ignored" )); + +if (is_shallow) { +int reject =0 ; + +/* If option_no_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ + +if (config_shallow !=-1 ) { + reject = config_shallow; + } +if (option_no_shallow !=-1 ) { + reject = option_no_shallow; + } +if (reject) { +die (_ ("source repository is shallow, reject to clone." )); + } + } + transport->cloning =1 ;transport_set_option (transport,TRANS_OPT_KEEP ,"yes" );
t/t5606-clone-options.sh +36 -0
@@ -45,6 +45,42 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' ' +test_expect_success 'fail to clone shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +' + +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repo + +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' + test_expect_success 'uses "origin" for default remote name' ' git clone parent clone-default-origin &&
t/t5611-clone-config.sh +32 -0
@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed cloning' ' + rm -rf child && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed cloning normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git clone -c clone.rejectshallow=false --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success ' option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
base-commit: fb7fa4a1fd273f22efcafdd13c7f897814fd1eb9
Signature · 1 line
gitgitgadget
Re: [PATCH v3] builtin/clone.c: add --reject-shallow option
Quoted 5 lines · Li Linchao via GitGitGadget
From: lilinchao <[email protected]>
In some scenarios, users may want more history than the repository offered for cloning, which mostly to be a shallow repository, can give them.
Sorry, but I find this hard to understand. Are you saying that most of the repositories that users try to clone from are shallow?
Quoted 4 lines
But users don't know it is a shallow repository until they download it to local, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
This one on the other hand is easy to understand, but we would probably need something like s/But/But because/.
Quoted 5 lines
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
Hmph, that is an interesting point. This makes me wonder if we can achieve the same without adding a new option at the UI level (e.g. by allowing "--depth" to take "infinity" and reject cloning if we find out that the origin repository is a shallow one). But we can worry about it later once after we get the machinery driven by the UI right.
Quoted 2 lines
In other scenarios, given that we have an API that allow us to import external repository, and then perform various operations on the repo.
Sorry, but I do not understand what you want to say with these two lines ("Given that X and Y" needs to be followed by a concluding statement, e.g. "Given that we have API to import and operate, we can do Z"---you are missing that "we can do Z" part).
Documentation/git-clone.txt SYNOPSIS · line 18
Quoted 10 lines
Documentation/git-clone.txt +1
-1@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--reject-shallow]
Isn't it "--[no-]reject-shallow"? Offering the negation from the command line is essential if "[clone] rejectshallow" configuration is allowed to set the default to true.
Quoted 7 lines
Documentation/git-clone.txt +7
-0+--reject-shallow:: + Don't clone a shallow source repository. In some scenarios, clients + want the cloned repository information to be complete. Otherwise, + the cloning process should end immediately without creating any files, + which can save some disk space. This can override `clone.rejectshallow` + from the configuration: +
Documentation/git-clone.txt objects from the source repository into a pack in the cloned repository. · line 168
Quoted 10 lines
Documentation/git-clone.txt +10
-0+ -------------------------------------------------------------------- + $ git -c clone.rejectshallow=false clone --reject-shallow source out + -------------------------------------------------------------------- + + While there is a way to countermand a configured "I always refuse to + clone from a shallow repository" with "but let's allow it only this time": + + ---------------------------------------------------------------------- + $ git -c clone.rejectshallow=true clone --no-reject-shallow source out + ----------------------------------------------------------------------
This is way too verbose and gives unnecessary details that readers already know or do not need to know (e.g. setting configuration from the command line and immediately override it from the command line is not something end-users would EVER need to do---only test writers who develop Git would need it). Something like
Fail if the source repository is a shallow repository. The clone.rejectShallow configuration variable can be used to give the default.
would be sufficient. All readers ought to know when a configuration and command line option exist, the latter can be used to override the default former gives, and it is *not* a job for the description of an individual option to teach them to such a detail like the above does.
Documentation/git-clone.txt
Quoted 2 lines
Documentation/git-clone.txt +2
-0+static int option_no_shallow = -1; /* unspecified */ +static int config_shallow = -1; /* unspecified */
Hmph. I would have expected the usual "prepare a single variable and initialize it to the default, read the config to set it, and then parse the command line to overwrite it" sequence would suffice so it is puzzling why we want two separate variables here.
Let's read on to find out.
Quoted 10 lines
Documentation/git-clone.txt +2
-0@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), OPT_BOOL(0, "progress", &option_progress, N_("force progress reporting")), + OPT_BOOL(0, "reject-shallow", &option_no_shallow, + N_("don't clone shallow repository")), OPT_BOOL('n', "no-checkout", &option_no_checkout, N_("don't create a checkout")), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
Documentation/git-clone.txt static int git_clone_config(const char *k, const char *v, void *cb) · line 869
Quoted 8 lines
Documentation/git-clone.txt +3
-0@@ -858,6 +862,9 @@ static int git_clone_config(const char *k, const char *v, void *cb) free(remote_name); remote_name = xstrdup(v); } + if (!strcmp(k, "clone.rejectshallow")) { + config_shallow = git_config_bool(k, v); + } return git_default_config(k, v, cb); }
You are adding to git_clone_config(), so instead of setting the value to config_shallow, setting the value to the same variable that will be used in builtin_clone_options[] array should be sufficient.
cmd_clone() begins like so:
git_config(git_clone_config, NULL); argc = parse_options(...);
which means that single variable (let's call it reject_shallow) can (1) stay to be its initial value if no config or option is given, (2) if there is config, the git_config() call will cause that variable assigned, (3) if there is option, parse_options() call will cause that variable assigned, possibly overwriting the value taken from the config.
Which is exactly what we want. So in short, declare just a single
static int reject_shallow; /* default to false */
instead of "option_no_shallow" and "config_shallow", and use it in both builtin_clone_options[] given to parse_options, and git_clone_config() that is given to git_config(), and you'd be fine, I think.
Quoted 9 lines
Documentation/git-clone.txt +1
-0@@ -963,6 +970,7 @@ static int path_exists(const char *path) int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; + int is_shallow = 0; const char *repo_name, *repo, *work_tree, *git_dir; char *path, *dir, *display_repo = NULL; int dest_exists, real_dest_exists = 0;
Documentation/git-clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1220
Quoted 8 lines
Documentation/git-clone.txt +5
-0@@ -1205,6 +1213,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path = get_repo_path(remote->url[0], &is_bundle); is_local = option_local != 0 && path && !is_bundle; + + /* Detect if the remote repository is shallow */ + if (!access(mkpath("%s/shallow", path), F_OK)) { + is_shallow = 1; + }
This is only for cloning from a local repository, no? IOW, path at this point may even be "git://github.com/git/git/" and checking with access() does not make sense.
Ah, it is even worse. get_repo_path() can return NULL, so mkpath() will crash in such a case. This must be at least
if (path && !access(mkpath("%s/shallow", path), F_OK))
is_shallow = 1;but I think the logic fits better in the body of "if (is_Local)" thing that immediately follows. It is specific to the case where cloning from a local repository and access(mkpath()) that is about the local filesystem (as opposed to going through the transport layer) belongs there.
Documentation/git-clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1234
Quoted 12 lines
Documentation/git-clone.txt +1
-1if (is_local) { if (option_depth) warning(_("--depth is ignored in local clones; use file:// instead."));@@ -1214,7 +1228,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) warning(_("--shallow-exclude is ignored in local clones; use file:// instead.")); if (filter_options.choice) warning(_("--filter is ignored in local clones; use file:// instead.")); - if (!access(mkpath("%s/shallow", path), F_OK)) { + if (is_shallow) { if (option_local > 0) warning(_("source repository is shallow, ignoring --local")); is_local = 0;
So, I think the above two hunks are making the code worse. If we are to detect and reject cloning from the shallow repository when going through the transport layer (i.e. "--no-local" or cloning from "git://github.com/git/git", or "https://github.com/git/git", if it were a shallow repository), that must be handled separately.
Quoted 8 lines
Documentation/git-clone.txt +4
-0@@ -1222,6 +1236,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } if (option_local > 0 && !is_local) warning(_("--local is ignored")); + + if (is_shallow) { + int reject = 0; +
Documentation/git-clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1252
Quoted 10 lines
Documentation/git-clone.txt +10
-0+ /* If option_no_shallow is specified from CLI option, + * ignore config_shallow from git_clone_config. + */ + + if (config_shallow != -1) { + reject = config_shallow; + } + if (option_no_shallow != -1) { + reject = option_no_shallow; + }
I do not think any of the above is necessary with just a single reject_shallow variable that is initialized to 0, can be set by git_config() callback, and can further be set by parse_options().
Quoted 9 lines
Documentation/git-clone.txt +5
-0+ if (reject) { + die(_("source repository is shallow, reject to clone.")); + } + } + transport->cloning = 1;
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
I do not see how this change would allow users to reject cloning
http://github.com/git/git, if that repository were shallow, though. I think that would need changes to the code that interacts with these transport_* functions we see later part of this functrion.
Thanks.
Re: Re: [PATCH v3] builtin/clone.c: add --reject-shallow option
In reply to a message not in the archive--------------
[email protected]
Quoted 11 lines
Quoted 5 lines · Li Linchao via GitGitGadget
From: lilinchao <[email protected]>
In some scenarios, users may want more history than the repository offered for cloning, which mostly to be a shallow repository, can give them.
Sorry, but I find this hard to understand. Are you saying that most of the repositories that users try to clone from are shallow?
Oh, sorry, it shoud be "which happens to be a shallow repository".
Quoted 8 lines
Quoted 4 lines
But users don't know it is a shallow repository until they download it to local, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
This one on the other hand is easy to understand, but we would probably need something like s/But/But because/.
Ok, I will substitute it.
Quoted 6 lines
Quoted 5 lines
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
Quoted 7 lines
Hmph, that is an interesting point. This makes me wonder if we can achieve the same without adding a new option at the UI level (e.g. by allowing "--depth" to take "infinity" and reject cloning if we find out that the origin repository is a shallow one). But we can worry about it later once after we get the machinery driven by the UI right.
Please let me explain the purpose of this patch in another way:
In practice, I may need a filter in clone command to filter out remote shallow repository that may appear. I think a new option like '--reject-shallow', or '--filter-shallow', or something like that, has a clearer purpose for users, they don't have to come up with a specific depth number to achieve the same purpose. A literal filter, or option is just ok, I think.
Quoted 8 lines
Quoted 2 lines
In other scenarios, given that we have an API that allow us to import external repository, and then perform various operations on the repo.
Sorry, but I do not understand what you want to say with these two lines ("Given that X and Y" needs to be followed by a concluding statement, e.g. "Given that we have API to import and operate, we can do Z"---you are missing that "we can do Z" part).
Forgive my crappy English :-(
What I want to express is "if we have an API to do sth, then do sth".
Quoted 6 lines
Quoted 6 lines
Documentation/git-clone.txt +0
-0@@ -15,7 +15,7 @@ SYNOPSIS[--dissociate] [--separate-git-dir <git dir>]
Quoted 9 lines
Documentation/git-clone.txt SYNOPSIS · line 18
Quoted 4 lines
[--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
Documentation/git-clone.txt +1
-1- [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--reject-shallow]Isn't it "--[no-]reject-shallow"? Offering the negation from the command line is essential if "[clone] rejectshallow" configuration is allowed to set the default to true.
Ok, that makes sense.
Quoted 74 lines
Quoted 7 lines
+--reject-shallow::
Documentation/git-clone.txt +6
-0+ Don't clone a shallow source repository. In some scenarios, clients + want the cloned repository information to be complete. Otherwise, + the cloning process should end immediately without creating any files, + which can save some disk space. This can override `clone.rejectshallow` + from the configuration: +Documentation/git-clone.txt objects from the source repository into a pack in the cloned repository. · line 168
Quoted 10 lines
Documentation/git-clone.txt +10
-0+ -------------------------------------------------------------------- + $ git -c clone.rejectshallow=false clone --reject-shallow source out + -------------------------------------------------------------------- + + While there is a way to countermand a configured "I always refuse to + clone from a shallow repository" with "but let's allow it only this time": + + ---------------------------------------------------------------------- + $ git -c clone.rejectshallow=true clone --no-reject-shallow source out + ----------------------------------------------------------------------This is way too verbose and gives unnecessary details that readers already know or do not need to know (e.g. setting configuration from the command line and immediately override it from the command line is not something end-users would EVER need to do---only test writers who develop Git would need it). Something like
Fail if the source repository is a shallow repository. The
clone.rejectShallowconfiguration variable can be used to give the default.would be sufficient. All readers ought to know when a configuration and command line option exist, the latter can be used to override the default former gives, and it is *not* a job for the description of an individual option to teach them to such a detail like the above does.
Documentation/git-clone.txt
Quoted 2 lines
Documentation/git-clone.txt +2
-0+static int option_no_shallow = -1; /* unspecified */ +static int config_shallow = -1; /* unspecified */Hmph. I would have expected the usual "prepare a single variable and initialize it to the default, read the config to set it, and then parse the command line to overwrite it" sequence would suffice so it is puzzling why we want two separate variables here.
Let's read on to find out.
Quoted 10 lines
Documentation/git-clone.txt +2
-0@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), OPT_BOOL(0, "progress", &option_progress, N_("force progress reporting")), + OPT_BOOL(0, "reject-shallow", &option_no_shallow, + N_("don't clone shallow repository")), OPT_BOOL('n', "no-checkout", &option_no_checkout, N_("don't create a checkout")), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),Documentation/git-clone.txt static int git_clone_config(const char *k, const char *v, void *cb) · line 869
Quoted 8 lines
Documentation/git-clone.txt +3
-0@@ -858,6 +862,9 @@ static int git_clone_config(const char *k, const char *v, void *cb) free(remote_name); remote_name = xstrdup(v); } + if (!strcmp(k, "clone.rejectshallow")) { + config_shallow = git_config_bool(k, v); + } return git_default_config(k, v, cb); }You are adding to
git_clone_config(), so instead of setting the value toconfig_shallow, setting the value to the same variable that will be used in builtin_clone_options[] array should be sufficient.
cmd_clone()begins like so:git_config(git_clone_config, NULL); argc = parse_options(...);
Quoted 7 lines
which means that single variable (let's call it
reject_shallow) can (1) stay to be its initial value if no config or option is given, (2) if there is config, thegit_config()call will cause that variable assigned, (3) if there is option,parse_options()call will cause that variable assigned, possibly overwriting the value taken from the config.
Sorry, you may forget there is a re-read git-config under these lines (around at line 1160):
/*
* additional config can be injected with -c, make sure it's included * after init_db, which clears the entire config environment. */ write_config(&option_config); /* * re-read config after init_db and write_config to pick up any config * injected by --template and --config, respectively. */ git_config(git_clone_config, NULL);
so, what I can think of is introducing a new variable for git_clone_config, and I find that in the other place, "define a new config_xxx variable for git-config" is usual.
Quoted 53 lines
Which is exactly what we want. So in short, declare just a single
static int
reject_shallow; /* default to false */
instead of "option_no_shallow" and "config_shallow", and use it in both builtin_clone_options[] given toparse_options, andgit_clone_config()that is given togit_config(), and you'd be fine, I think.Quoted 12 lines
Documentation/git-clone.txt +1
-0@@ -963,6 +970,7 @@ static int path_exists(const char *path) int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; + int is_shallow = 0; const char *repo_name, *repo, *work_tree, *git_dir; char *path, *dir, *display_repo = NULL; int dest_exists, real_dest_exists = 0;@@ -1205,6 +1213,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
path =get_repo_path(remote->url[0], &is_bundle);is_local=option_local!= 0 && path && !is_bundle;Documentation/git-clone.txt
Quoted 5 lines
Documentation/git-clone.txt +5
-0+ + /* Detect if the remote repository is shallow */ + if (!access(mkpath("%s/shallow", path), F_OK)) { + is_shallow = 1; + }This is only for cloning from a local repository, no? IOW, path at this point may even be "
git://github.com/git/git/" and checking withaccess()does not make sense.Ah, it is even worse.
get_repo_path()can return NULL, somkpath()will crash in such a case. This must be at leastif (path && !access(mkpath("%s/shallow", path), F_OK)) is_shallow = 1;but I think the logic fits better in the body of "if (
is_Local)" thing that immediately follows. It is specific to the case where cloning from a local repository and access(mkpath()) that is about the local filesystem (as opposed to going through the transport layer) belongs there.Quoted 10 lines
if (
is_local) {
if (option_depth)
warning(_("--depth is ignored in local clones; use file:// instead."));Documentation/git-clone.txt +1
-1@@ -1214,7 +1228,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) warning(_("--shallow-exclude is ignored in local clones; use file:// instead.")); if (filter_options.choice) warning(_("--filter is ignored in local clones; use file:// instead.")); - if (!access(mkpath("%s/shallow", path), F_OK)) { + if (is_shallow) { if (option_local > 0)
Quoted 9 lines
Documentation/git-clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1234
Quoted 2 lines
Documentation/git-clone.txt +0
-0warning(_("source repository is shallow, ignoring --local")); is_local = 0;So, I think the above two hunks are making the code worse. If we are to detect and reject cloning from the shallow repository when going through the transport layer (i.e. "--no-local" or cloning from "
git://github.com/git/git", or "https://github.com/git/git", if it were a shallow repository), that must be handled separately.
Sorry, I made the question simple. Reject cloning a shallow repository should apply to all four type transport protocols. There still a bunch of work to be done.
Quoted 38 lines
Quoted 8 lines
Documentation/git-clone.txt +4
-0@@ -1222,6 +1236,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } if (option_local > 0 && !is_local) warning(_("--local is ignored")); + + if (is_shallow) { + int reject = 0; +Documentation/git-clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1252
Quoted 10 lines
Documentation/git-clone.txt +10
-0+ /* If option_no_shallow is specified from CLI option, + * ignore config_shallow from git_clone_config. + */ + + if (config_shallow != -1) { + reject = config_shallow; + } + if (option_no_shallow != -1) { + reject = option_no_shallow; + }I do not think any of the above is necessary with just a single
reject_shallowvariable that is initialized to 0, can be set bygit_config()callback, and can further be set byparse_options().Quoted 9 lines
Documentation/git-clone.txt +5
-0+ if (reject) { + die(_("source repository is shallow, reject to clone.")); + } + } + transport->cloning = 1;
transport_set_option(transport, TRANS_OPT_KEEP, "yes");I do not see how this change would allow users to reject cloning
http://github.com/git/git, if that repository were shallow, though. I think that would need changes to the code that interacts with these transport_* functions we see later part of this functrion.
Quoted 1 line
Thanks.
On the whole, thank you for all your patience and suggestions! I will dig into the code, and base on your suggestions to figure it out.
Finally, I wish you a Happy Lunar New Year! ^-^
-Lilinchao
Re: [PATCH v3] builtin/clone.c: add --reject-shallow option
Quoted 1 line · "[email protected]" <[email protected]> writes:
Sorry, you may forget there is a re-read git-config under these lines
Ahhhh, thanks. You're right that "clone" is "special" in that way and requires unusual order---I forgot about that.
Quoted 17 lines
Quoted 9 lines
This is only for cloning from a local repository, no? IOW, path at this point may even be "
git://github.com/git/git/" and checking withaccess()does not make sense.Ah, it is even worse.
get_repo_path()can return NULL, somkpath()will crash in such a case. This must be at leastif (path && !access(mkpath("%s/shallow", path), F_OK)) is_shallow = 1;Quoted 8 lines
...
So, I think the above two hunks are making the code worse. If we are to detect and reject cloning from the shallow repository when going through the transport layer (i.e. "--no-local" or cloning from "
git://github.com/git/git", or "https://github.com/git/git", if it were a shallow repository), that must be handled separately.
Quoted 3 lines
Sorry, I made the question simple. Reject cloning a shallow repository should apply to all four type transport protocols. There still a bunch of work to be done.
Sorry, but I didn't realize that this is just a work-in-progress that shows an early "only local transport is covered" preview. I think, modulo that the access(mkpath()) thing should be in the "if (is_local)" block, the patch covers the case of local transport well enough. I think by "four types of transport" you mean ssh://, git://
https:// etc., but they all go through the same transport API, so hopefully once one of them, say, git://, is covered, that would take us a long way.
Thanks.
Re: Re: [PATCH v3] builtin/clone.c: add --reject-shallow option
In reply to a message not in the archive--------------
[email protected]
Quoted 28 lines
Quoted 1 line · "[email protected]" <[email protected]> writes:
Sorry, you may forget there is a re-read git-config under these lines
Ahhhh, thanks. You're right that "clone" is "special" in that way and requires unusual order---I forgot about that.
Quoted 17 lines
Quoted 9 lines
This is only for cloning from a local repository, no? IOW, path at this point may even be "
git://github.com/git/git/" and checking withaccess()does not make sense.Ah, it is even worse.
get_repo_path()can return NULL, somkpath()will crash in such a case. This must be at leastif (path && !access(mkpath("%s/shallow", path), F_OK)) is_shallow = 1;Quoted 8 lines
...
So, I think the above two hunks are making the code worse. If we are to detect and reject cloning from the shallow repository when going through the transport layer (i.e. "--no-local" or cloning from "
git://github.com/git/git", or "https://github.com/git/git", if it were a shallow repository), that must be handled separately.Quoted 3 lines
Sorry, I made the question simple. Reject cloning a shallow repository should apply to all four type transport protocols. There still a bunch of work to be done.
Quoted 9 lines
Sorry, but I didn't realize that this is just a work-in-progress that shows an early "only local transport is covered" preview. I think, modulo that the access(mkpath()) thing should be in the "if (
is_local)" block, the patch covers the case of local transport well enough. I think by "four types of transport" you mean ssh://,git://
https:// etc., but they all go through the same transport API, so hopefully once one of them, say,git://, is covered, that would take us a long way.
Hi, after some exploration, I found that the following changes
can achieve the goal:
(around at line 1386 in builtin/clone.c)
/* below part is my changes */
if (reject_shallow) {
if (local_shallow || is_repository_shallow(the_repository)) { die(_("source repository is shallow, reject to clone.")); }
}
/* end */
update_remote_refs(refs, mapped_refs, remote_head_points_at, branch_top.buf, reflog_msg.buf, transport, !is_local);
as it shows, using existing method "is_repository_shallow" to detect whether the repo is shallow or not, before "update_remote_refs" I made some tests based on this change, and it seems ok. what do you think about this?
Quoted 1 line
Thanks.
PATCH v4 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v3:
1: f5ed6b2e4481 ! 1: ee4fb840a32f builtin/clone.c: add --reject-shallow option
@@ Commit message
builtin/clone.c: add --reject-shallow option
In some scenarios, users may want more history than the repository
- offered for cloning, which mostly to be a shallow repository, can
- give them. But users don't know it is a shallow repository until
- they download it to local, users should have the option to refuse
- to clone this kind of repository, and may want to exit the process
- immediately without creating any unnecessary files.
+ 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, users should have the option to
+ refuse to clone this kind of repository, and may want to exit the
+ process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how
deep history they can fetch, but as the unshallow cloning's depth
@@ Commit message
satisfy the minimum integrity, so we can't pass 'x' value to --depth,
and expect this can obtain a complete history of a repository.
- In other scenarios, given that we have an API that allow us to import
- external repository, and then perform various operations on the repo.
+ In other scenarios, if we have an API that allow us to import external
+ repository, and then perform various operations on the repo.
But if the imported is a shallow one(which is actually possible), it
will affect the subsequent operations. So we can choose to refuse to
- clone, and let's just import an unshallow repository.
+ clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to
clone a shallow repository.
@@ Documentation/git-clone.txt: SYNOPSIS
[--depth <depth>] [--[no-]single-branch] [--no-tags]
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
- [--[no-]remote-submodules] [--jobs <n>] [--sparse]
-+ [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--reject-shallow]
++ [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
[--filter=<filter>] [--] <repository>
[<directory>]
@@ Documentation/git-clone.txt: objects from the source repository into a pack in t
--no-checkout::
No checkout of HEAD is performed after the clone is complete.
-+--reject-shallow::
-+ Don't clone a shallow source repository. In some scenarios, clients
-+ want the cloned repository information to be complete. Otherwise,
-+ the cloning process should end immediately without creating any files,
-+ which can save some disk space. This can override `clone.rejectshallow`
-+ from the configuration:
-+
-+ --------------------------------------------------------------------
-+ $ git -c clone.rejectshallow=false clone --reject-shallow source out
-+ --------------------------------------------------------------------
-+
-+ While there is a way to countermand a configured "I always refuse to
-+ clone from a shallow repository" with "but let's allow it only this time":
-+
-+ ----------------------------------------------------------------------
-+ $ git -c clone.rejectshallow=true clone --no-reject-shallow source out
-+ ----------------------------------------------------------------------
++--[no-]reject-shallow::
++ Fail if the source repository is a shallow repository. The
++ 'clone.rejectshallow' configuration variable can be used to
++ give the default.
+
--bare::
Make a 'bare' Git repository. That is, instead of
creating `<directory>` and placing the administrative
## builtin/clone.c ##
+@@
+ #include "connected.h"
+ #include "packfile.h"
+ #include "list-objects-filter-options.h"
++#include "shallow.h"
+
+ /*
+ * Overall FIXMEs:
@@ builtin/clone.c: 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_no_tags;
static int option_shallow_submodules;
-+static int option_no_shallow = -1; /* unspecified */
++static int option_shallow = -1; /* unspecified */
+static int config_shallow = -1; /* unspecified */
static int deepen;
static char *option_template, *option_depth, *option_since;
@@ builtin/clone.c: static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
N_("force progress reporting")),
-+ OPT_BOOL(0, "reject-shallow", &option_no_shallow,
++ OPT_BOOL(0, "reject-shallow", &option_shallow,
+ N_("don't clone shallow repository")),
OPT_BOOL('n', "no-checkout", &option_no_checkout,
N_("don't create a checkout")),
@@ builtin/clone.c: static int path_exists(const char *path)
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
-+ int is_shallow = 0;
++ int local_shallow = 0;
++ int reject_shallow = 0;
const char *repo_name, *repo, *work_tree, *git_dir;
char *path, *dir, *display_repo = NULL;
int dest_exists, real_dest_exists = 0;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
+ */
+ git_config(git_clone_config, NULL);
- path = get_repo_path(remote->url[0], &is_bundle);
- is_local = option_local != 0 && path && !is_bundle;
-+
-+ /* Detect if the remote repository is shallow */
-+ if (!access(mkpath("%s/shallow", path), F_OK)) {
-+ is_shallow = 1;
++ /*
++ * If option_shallow is specified from CLI option,
++ * ignore config_shallow from git_clone_config.
++ */
++ if (config_shallow != -1) {
++ reject_shallow = config_shallow;
+ }
-+
- if (is_local) {
- if (option_depth)
- warning(_("--depth is ignored in local clones; use file:// instead."));
++ if (option_shallow != -1) {
++ reject_shallow = option_shallow;
++ }
+ /*
+ * apply the remote name provided by --origin only after this second
+ * call to git_config, to ensure it overrides all config-based values.
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
- warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
if (filter_options.choice)
warning(_("--filter is ignored in local clones; use file:// instead."));
-- if (!access(mkpath("%s/shallow", path), F_OK)) {
-+ if (is_shallow) {
+ if (!access(mkpath("%s/shallow", path), F_OK)) {
++ local_shallow = 1;
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
+ goto cleanup;
}
- if (option_local > 0 && !is_local)
- warning(_("--local is ignored"));
-+
-+ if (is_shallow) {
-+ int reject = 0;
-+
-+ /* If option_no_shallow is specified from CLI option,
-+ * ignore config_shallow from git_clone_config.
-+ */
-+
-+ if (config_shallow != -1) {
-+ reject = config_shallow;
-+ }
-+ if (option_no_shallow != -1) {
-+ reject = option_no_shallow;
-+ }
-+ if (reject) {
+
++ if (reject_shallow) {
++ if (local_shallow || is_repository_shallow(the_repository)) {
+ die(_("source repository is shallow, reject to clone."));
+ }
+ }
+
- transport->cloning = 1;
-
- transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+ update_remote_refs(refs, mapped_refs, remote_head_points_at,
+ branch_top.buf, reflog_msg.buf, transport,
+ !is_local);
## t/t5606-clone-options.sh ##
+@@ t/t5606-clone-options.sh: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+ . ./test-lib.sh
++. "$TEST_DIRECTORY"/lib-httpd.sh
++start_httpd
+
+ test_expect_success 'setup' '
+
@@ t/t5606-clone-options.sh: test_expect_success 'disallows --bare with --separate-git-dir' '
'
++test_expect_success 'fail to clone http shallow repository' '
++ git clone --depth=1 --no-local parent shallow-repo &&
++ git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
++ test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err &&
++ test_i18ngrep -e "source repository is shallow, reject to clone." err
++
++'
++
+test_expect_success 'fail to clone shallow repository' '
++ rm -rf shallow-repo &&
+ git clone --depth=1 --no-local parent shallow-repo &&
+ test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
+ test_i18ngrep -e "source repository is shallow, reject to clone." err
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
+ test_i18ngrep -e "source repository is shallow, reject to clone." err
+'
+
-+test_expect_success 'clone.rejectshallow=false should succeed cloning' '
++test_expect_success 'clone.rejectshallow=false should succeed' '
+ rm -rf child &&
+ git clone --depth=1 --no-local . child &&
+ git -c clone.rejectshallow=false clone --no-local child out
+'
+
-+test_expect_success 'clone.rejectshallow=true should succeed cloning normal repo' '
++test_expect_success 'clone.rejectshallow=true should succeed with normal repo' '
+ rm -rf child out &&
+ git clone --no-local . child &&
+ git -c clone.rejectshallow=true clone --no-local child out
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
+test_expect_success 'option --reject-shallow override clone.rejectshallow' '
+ rm -rf child out &&
+ git clone --depth=1 --no-local . child &&
-+ test_must_fail git clone -c clone.rejectshallow=false --reject-shallow --no-local child out 2>err &&
++ test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err &&
+ test_i18ngrep -e "source repository is shallow, reject to clone." err
+'
+
-+test_expect_success ' option --no-reject-shallow override clone.rejectshallow' '
++test_expect_success 'option --no-reject-shallow override clone.rejectshallow' '
+ rm -rf child &&
+ git clone --depth=1 --no-local . child &&
+ git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child outDocumentation/config/clone.txt | 4 +++ Documentation/git-clone.txt | 7 ++++- builtin/clone.c | 27 +++++++++++++++++++ t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ 5 files changed, 116 insertions(+), 1 deletion(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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 + give the default. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +27 -0
@@ -32,6 +32,7 @@#include "connected.h" #include "packfile.h" #include "list-objects-filter-options.h" +#include "shallow.h" /* * Overall FIXMEs:
@@ -50,6 +51,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +93,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ -858,6 +863,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + config_shallow =git_config_bool (k, v); + }return git_default_config (k, v, cb); }
@@ -963,6 +971,8 @@ static int path_exists(const char *path)int cmd_clone (int argc,const char **argv,const char *prefix) {int is_bundle =0 , is_local; +int local_shallow =0 ; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1156,6 +1166,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) { + reject_shallow = config_shallow; + } +if (option_shallow !=-1 ) { + reject_shallow = option_shallow; + }/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values.
@@ -1216,6 +1236,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { + local_shallow =1 ;if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1363,6 +1384,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) goto cleanup; } +if (reject_shallow) { +if (local_shallow ||is_repository_shallow (the_repository)) { +die (_ ("source repository is shallow, reject to clone." )); + } + } +update_remote_refs (refs, mapped_refs, remote_head_points_at, branch_top.buf, reflog_msg.buf, transport, !is_local);
t/t5606-clone-options.sh +47 -0
59 lines not on this page · raw message
t/t5611-clone-config.sh +32 -0
@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
base-commit: 2283e0e9af55689215afa39c03beb2315ce18e83
Signature · 1 line
gitgitgadget
Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
[jc: I've CC'ed Jonathan Tan, who is much more knowledgeable than I am on the transport layer issues, to sanity check my assumption]
builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1388
Quoted 6 lines · Li Linchao via GitGitGadget
builtin/clone.c +2
-0@@ -1363,6 +1384,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) goto cleanup; } +if (reject_shallow) { +if (local_shallow ||is_repository_shallow (the_repository)) {
This may reject to clone from a shallow repository, but at this point the bulk of the tranfer from the origin repository has already happened, no? Rejecting after transferring many megabytes feels a bit too late. That is one of the reasons why I kept hinting that the transport layer needs to be taught an option to reject talking to a shallow counterpart if we want to add this feature [*1*].
Also, wouldn't "clone --depth=1 --reject-shallow" from a repository that is not shallow make the_repository a shallow one at this point and makes it fail? If the goal of the --reject-shallow option were to make sure the resulting repository is not shallow, then that is a technically correct implementation (even though it is wasteful to transfer a full tree worth of megabytes and then abort), but is the feature is explained to reject cloning from a shallow one, then users would be suprised to see ...
builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1389
Quoted 1 line
builtin/clone.c +1
-0+die (_ ("source repository is shallow, reject to clone." ));
... this message, when cloning from well known publich repositories that are not shallow.
I think cloning with --depth=<n> when the source repository is deep enough, should be allowed, so the cleanest solution for the latter may be to notice the combination of options that make the resulting repository shallow (I mentioned --depth=<n>, but there may be others) and the --reject-shallow option and error out before even talking to the other side at the time we parse the command line.
Thanks.
[Footnote]
*1* Looking at Documentation/technical/pack-protocol.txt, "git
fetch" seem to learn if the repository is shallow immediately upon contacting "upload-pack" during the Reference Discovery phase (we'd see 'shallow' packets if they are shallow). I suspect that the right solution would be to teach the codepath on the "git fetch" side that accepts, parses, and acts on this packet to optionally stop communication and error out when the caller asks not to talk with a shallow repository.
Re: Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
In reply to a message not in the archive--------------
[email protected]
Quoted 28 lines
[jc: I've CC'ed Jonathan Tan, who is much more knowledgeable than I am on the transport layer issues, to sanity check my assumption]
builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1388
Quoted 6 lines · Li Linchao via GitGitGadget
builtin/clone.c +0
-0@@ -1363,6 +1384,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) goto cleanup; }builtin/clone.c +2
-0+if (reject_shallow) { +if (local_shallow ||is_repository_shallow (the_repository)) {This may reject to clone from a shallow repository, but at this point the bulk of the tranfer from the origin repository has already happened, no? Rejecting after transferring many megabytes feels a bit too late. That is one of the reasons why I kept hinting that the transport layer needs to be taught an option to reject talking to a shallow counterpart if we want to add this feature [*1*].
Also, wouldn't "clone --depth=1 --reject-shallow" from a repository that is not shallow make
the_repositorya shallow one at this point and makes it fail? If the goal of the --reject-shallow option were to make sure the resulting repository is not shallow, then that is a technically correct implementation (even though it is wasteful to transfer a full tree worth of megabytes and then abort), but is the feature is explained to reject cloning from a shallow one, then users would be suprised to see ...
Quoted 5 lines
builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1389
Quoted 1 line
builtin/clone.c +1
-0+die (_ ("source repository is shallow, reject to clone." ));... this message, when cloning from well known publich repositories that are not shallow.
Uh, IMO the goal of this new option is not to make sure the cloned repo is not shallow, but to prevent(just as optional) the remote repo is shallow, we still allow the resulting repo is shallow by using "--depth" option. so, if we apply "clone --depth=1 --reject-shallow=true" to a clone process, the expected result is a shallow repo.
Oh, wait, what if we apply "--depth=1" to a remote shallow repo, in other word, shallow a remote shallow repo? then the result will not be what we expected. This can be confusing.
Quoted 12 lines
I think cloning with --depth=<n> when the source repository is deep enough, should be allowed, so the cleanest solution for the latter may be to notice the combination of options that make the resulting repository shallow (I mentioned --depth=<n>, but there may be others) and the --reject-shallow option and error out before even talking to the other side at the time we parse the command line.
Thanks.
[Footnote]
Quoted 8 lines
*1* Looking at
Documentation/technical/pack-protocol.txt, "git fetch" seem to learn if the repository is shallow immediately upon contacting "upload-pack" during the Reference Discovery phase (we'd see 'shallow' packets if they are shallow). I suspect that the right solution would be to teach the codepath on the "git fetch" side that accepts, parses, and acts on this packet to optionally stop communication and error out when the caller asks not to talk with a shallow repository.
I took the time to update the patch as you suggested there, it may look imperfect, I only tested the local protocol, and the smart protocols, not dumb protocol, and not protocol version1 yet.
Hope to get some suggestions from you.
PATCH v5 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v4:
1: ee4fb840a32f ! 1: 3f765e49e4a7 builtin/clone.c: add --reject-shallow option
@@ Documentation/git-clone.txt: objects from the source repository into a pack in t
creating <directory> and placing the administrative
## builtin/clone.c ##
-@@
- #include "connected.h"
- #include "packfile.h"
- #include "list-objects-filter-options.h"
-+#include "shallow.h"
-
- /*
- * Overall FIXMEs:
@@ builtin/clone.c: 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_no_tags;
@@ builtin/clone.c: static int path_exists(const char *path)
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
-+ int local_shallow = 0;
+ int reject_shallow = 0;
const char *repo_name, *repo, *work_tree, *git_dir;
char *path, *dir, *display_repo = NULL;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
if (filter_options.choice)
warning(_("--filter is ignored in local clones; use file:// instead."));
if (!access(mkpath("%s/shallow", path), F_OK)) {
-+ local_shallow = 1;
++ if (reject_shallow)
++ die("source repository is shallow, reject to clone.");
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
- goto cleanup;
- }
-+ if (reject_shallow) {
-+ if (local_shallow || is_repository_shallow(the_repository)) {
-+ die(_("source repository is shallow, reject to clone."));
-+ }
-+ }
+ transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+
++ if (reject_shallow)
++ transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
+ if (option_depth)
+ transport_set_option(transport, TRANS_OPT_DEPTH,
+ option_depth);
+
+ ## fetch-pack.c ##
+@@ fetch-pack.c: static struct ref *do_fetch_pack(struct fetch_pack_args *args, +
+ if (args->stateless_rpc)
+ packet_flush(fd[1]);
++
++ if (!args->deepen && args->remote_shallow)
++ die("source repository is shallow, reject to clone.");
+
- update_remote_refs(refs, mapped_refs, remote_head_points_at,
- branch_top.buf, reflog_msg.buf, transport,
- !is_local);
+ if (args->deepen)
+ setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
+ NULL);
+@@ fetch-pack.c: static void receive_shallow_info(struct fetch_pack_args *args,
+ * shallow. In v0, remote refs that reach these objects are
+ * rejected (unless --update-shallow is set); do the same.
+ */
++ if (args->remote_shallow)
++ die("source repository is shallow, reject to clone.");
+ prepare_shallow_info(si, shallows);
+ if (si->nr_ours || si->nr_theirs)
+ alternate_shallow_file =
+
+ ## fetch-pack.h ##
+@@ fetch-pack.h: struct fetch_pack_args {
+ unsigned self_contained_and_connected:1;
+ unsigned cloning:1;
+ unsigned update_shallow:1;
++ unsigned remote_shallow:1;
+ unsigned deepen:1;
+
+ /*
## t/t5606-clone-options.sh ##
@@ t/t5606-clone-options.sh: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
+'
+
+test_expect_success 'clone.rejectshallow=false should succeed' '
-+ rm -rf child &&
++ rm -rf child out &&
+ git clone --depth=1 --no-local . child &&
+ git -c clone.rejectshallow=false clone --no-local child out
+'
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
+'
+
+test_expect_success 'option --no-reject-shallow override clone.rejectshallow' '
-+ rm -rf child &&
++ rm -rf child out &&
+ git clone --depth=1 --no-local . child &&
+ git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out
+'
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
test_expect_success MINGW 'clone -c core.hideDotFiles' '
test_commit attributes .gitattributes "" &&
rm -rf child &&
+
+ ## transport-helper.c ##
+@@ transport-helper.c: static const char *boolean_options[] = {
+ TRANS_OPT_THIN,
+ TRANS_OPT_KEEP,
+ TRANS_OPT_FOLLOWTAGS,
+- TRANS_OPT_DEEPEN_RELATIVE
++ TRANS_OPT_DEEPEN_RELATIVE,
++ TRANS_OPT_REJECT_SHALLOW
+ };
+
+ static int strbuf_set_helper_option(struct helper_data *data,
+
+ ## transport.c ##
+@@ transport.c: static int set_git_option(struct git_transport_options *opts,
+ list_objects_filter_die_if_populated(&opts->filter_options);
+ parse_list_objects_filter(&opts->filter_options, value);
+ return 0;
++ } else if (!strcmp(name, TRANS_OPT_REJECT_SHALLOW)) {
++ opts->reject_shallow = !!value;
++ return 0;
+ }
+ return 1;
+ }
+@@ transport.c: static int fetch_refs_via_pack(struct transport *transport,
+ args.stateless_rpc = transport->stateless_rpc;
+ args.server_options = transport->server_options;
+ args.negotiation_tips = data->options.negotiation_tips;
++ args.remote_shallow = transport->smart_options->reject_shallow;
+
+ if (!data->got_remote_heads) {
+ int i;
+
+ ## transport.h ##
+@@ transport.h: struct git_transport_options {
+ unsigned check_self_contained_and_connected : 1;
+ unsigned self_contained_and_connected : 1;
+ unsigned update_shallow : 1;
++ unsigned reject_shallow : 1;
+ unsigned deepen_relative : 1;
+
+ /* see documentation of corresponding flag in fetch-pack.h */
+@@ transport.h: void transport_check_allowed(const char *type);
+ /* Aggressively fetch annotated tags if possible */
+ #define TRANS_OPT_FOLLOWTAGS "followtags"
+
++/* reject shallow repo transport */
++#define TRANS_OPT_REJECT_SHALLOW "rejectshallow"
++
+ /* Accept refs that may update .git/shallow without --depth */
+ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
+
Documentation/config/clone.txt | 4 +++ Documentation/git-clone.txt | 7 ++++- builtin/clone.c | 22 ++++++++++++++++ fetch-pack.c | 6 +++++ fetch-pack.h | 1 + t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ transport-helper.c | 3 ++- transport.c | 4 +++ transport.h | 4 +++ 10 files changed, 128 insertions(+), 2 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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 + give the default. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +22 -0
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + config_shallow =git_config_bool (k, v); + }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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) { + reject_shallow = config_shallow; + } +if (option_shallow !=-1 ) { + reject_shallow = option_shallow; + }/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values.
@@ -1216,6 +1234,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die ("source repository is shallow, reject to clone." );if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1227,6 +1247,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);
fetch-pack.c +6 -0
@@ -1071,6 +1071,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->stateless_rpc)packet_flush (fd[1 ]); + +if (!args->deepen && args->remote_shallow) +die ("source repository is shallow, reject to clone." ); +if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL );
@@ -1440,6 +1444,8 @@ static void receive_shallow_info(struct fetch_pack_args *args,* shallow. In v0, remote refs that reach these objects are * rejected (unless --update-shallow is set); do the same. */ +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." );prepare_shallow_info (si, shallows);if (si->nr_ours || si->nr_theirs) alternate_shallow_file =
fetch-pack.h +1 -0
@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/*
t/t5606-clone-options.sh +47 -0
59 lines not on this page · raw message
t/t5611-clone-config.sh +32 -0
@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
transport-helper.c +2 -1
@@ -265,7 +265,8 @@ static const char *boolean_options[] = {TRANS_OPT_THIN ,TRANS_OPT_KEEP ,TRANS_OPT_FOLLOWTAGS , -TRANS_OPT_DEEPEN_RELATIVE +TRANS_OPT_DEEPEN_RELATIVE , +TRANS_OPT_REJECT_SHALLOW }; static int strbuf_set_helper_option(struct helper_data *data,
transport.c +4 -0
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;
transport.h +4 -0
@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
base-commit: 225365fb5195e804274ab569ac3cc4919451dc7f
Signature · 1 line
gitgitgadget
Re: [PATCH v5] builtin/clone.c: add --reject-shallow option
--------------
[email protected]
Quoted 344 lines
From: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
Signed-off-by lilinchao <[email protected]>---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.Signed-off-by lilinchao [email protected]Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/865Range-diff vs v4:
1:
ee4fb840a32f! 1:3f765e49e4a7builtin/clone.c: add --reject-shallow option
@@Documentation/git-clone.txt: objects from the source repository into a pack in t creating<directory>and placing the administrative
##builtin/clone.c##
-@@
- #include "connected.h"
- #include "packfile.h"
- #include "list-objects-filter-options.h"
-+#include "shallow.h"
-
- /*
- * Overall FIXMEs:
@@builtin/clone.c: static intoption_no_checkout,option_bare,option_mirror,option_single_branchstatic intoption_local= -1,option_no_hardlinks,option_shared;
static intoption_no_tags;
@@builtin/clone.c: static intpath_exists(const char *path)
intcmd_clone(int argc, const char **argv, const char *prefix)
{
intis_bundle= 0,is_local;
-+ intlocal_shallow= 0;
+ intreject_shallow= 0;
const char*repo_name, *repo,*work_tree,*git_dir;
char *path, *dir,*display_repo= NULL;
@@builtin/clone.c: intcmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)
warning(_("--filter is ignored in local clones; use file:// instead."));
if (!access(mkpath("%s/shallow", path),F_OK)) {
-+local_shallow= 1;
++ if (reject_shallow)
++die("source repository is shallow, reject to clone.");
if (option_local> 0)
warning(_("source repository is shallow, ignoring --local"));
is_local= 0;
@@builtin/clone.c: intcmd_clone(int argc, const char **argv, const char *prefix)
- goto cleanup;
- }
-+ if (reject_shallow) {
-+ if (local_shallow||is_repository_shallow(the_repository)) {
-+die(_("source repository is shallow, reject to clone."));
-+ }
-+ }
+transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+
++ if (reject_shallow)
++transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
+ if (option_depth)
+ transport_set_option(transport,TRANS_OPT_DEPTH,
+option_depth);
+
+ ##fetch-pack.c##
+@@fetch-pack.c: static struct ref *do_fetch_pack(structfetch_pack_args*args,
+
+ if (args->stateless_rpc)
+packet_flush(fd[1]);
++
++ if (!args->deepen &&args->remote_shallow)
++die("source repository is shallow, reject to clone.");
+
- update_remote_refs(refs,mapped_refs,remote_head_points_at,
- branch_top.buf, reflog_msg.buf, transport,
- !is_local);
+ if (args->deepen)
+ setup_alternate_shallow(&shallow_lock,&alternate_shallow_file,
+ NULL);
+@@fetch-pack.c: static void receive_shallow_info(structfetch_pack_args*args,
+ * shallow. In v0, remote refs that reach these objects are
+ * rejected (unless --update-shallow is set); do the same.
+ */
++ if (args->remote_shallow)
++die("source repository is shallow, reject to clone.");
+prepare_shallow_info(si, shallows);
+ if (si->nr_ours||si->nr_theirs)
+alternate_shallow_file=
+
+ ##fetch-pack.h##
+@@fetch-pack.h: structfetch_pack_args{
+ unsigned self_contained_and_connected:1;
+ unsigned cloning:1;
+ unsigned update_shallow:1;
++ unsigned remote_shallow:1;
+ unsigned deepen:1;
+
+ /*
##t/t5606-clone-options.sh##
@@t/t5606-clone-options.sh: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
@@t/t5611-clone-config.sh:test_expect_success'clone -c remote.<remote>.fetch=<re +'
+
+test_expect_success 'clone.rejectshallow=false should succeed' '
-+ rm -rf child &&
++ rm -rf child out &&
+ git clone --depth=1 --no-local . child &&
+ git -c clone.rejectshallow=false clone --no-local child out
+'
@@t/t5611-clone-config.sh:test_expect_success'clone -c remote.<remote>.fetch=<re +'
+
+test_expect_success 'option --no-reject-shallow override clone.rejectshallow' '
-+ rm -rf child &&
++ rm -rf child out &&
+ git clone --depth=1 --no-local . child &&
+ git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out
+'
@@t/t5611-clone-config.sh:test_expect_success'clone -c remote.<remote>.fetch=<retest_expect_successMINGW 'clone -c core.hideDotFiles' '
test_commitattributes .gitattributes "" &&
rm -rf child &&
+
+ ##transport-helper.c##
+@@transport-helper.c: static const char *boolean_options[] = {
+TRANS_OPT_THIN,
+TRANS_OPT_KEEP,
+TRANS_OPT_FOLLOWTAGS,
+-TRANS_OPT_DEEPEN_RELATIVE
++TRANS_OPT_DEEPEN_RELATIVE,
++TRANS_OPT_REJECT_SHALLOW
+ };
+
+ static int strbuf_set_helper_option(structhelper_data*data,
+
+ ##transport.c##
+@@transport.c: static int set_git_option(structgit_transport_options*opts,
+list_objects_filter_die_if_populated(&opts->filter_options);
+parse_list_objects_filter(&opts->filter_options, value);
+ return 0;
++ } else if (!strcmp(name,TRANS_OPT_REJECT_SHALLOW)) {
++opts->reject_shallow= !!value;
++ return 0;
+ }
+ return 1;
+ }
+@@transport.c: static int fetch_refs_via_pack(struct transport *transport,
+ args.stateless_rpc =transport->stateless_rpc;
+ args.server_options =transport->server_options;
+ args.negotiation_tips =data->options.negotiation_tips;
++ args.remote_shallow =transport->smart_options->reject_shallow;
+
+ if (!data->got_remote_heads) {
+ int i;
+
+ ##transport.h##
+@@transport.h: structgit_transport_options{
+ unsignedcheck_self_contained_and_connected: 1;
+ unsignedself_contained_and_connected: 1;
+ unsignedupdate_shallow: 1;
++ unsignedreject_shallow: 1;
+ unsigneddeepen_relative: 1;
+
+ /* see documentation of corresponding flag infetch-pack.h*/
+@@transport.h: voidtransport_check_allowed(const char *type);
+ /* Aggressively fetch annotated tags if possible */
+ #defineTRANS_OPT_FOLLOWTAGS"followtags"
+
++/* reject shallow repo transport */
++#defineTRANS_OPT_REJECT_SHALLOW"rejectshallow"
++
+ /* Accept refs that may update .git/shallow without --depth */
+ #defineTRANS_OPT_UPDATE_SHALLOW"updateshallow"
+
Documentation/config/clone.txt| 4 +++ Documentation/git-clone.txt | 7 ++++-
builtin/clone.c | 22 ++++++++++++++++ fetch-pack.c | 6 +++++
fetch-pack.h | 1 + t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ transport-helper.c | 3 ++-
transport.c | 4 +++
transport.h | 4 +++10 files changed, 128 insertions(+), 2 deletions(-)Documentation/config/clone.txt +0
-0@@ -2,3 +2,7 @@ clone.defaultRemoteName::The name of the remote to create when cloning a repository. Defaults to
origin, and can be overridden by passing the--origincommand-line option to linkgit:git-clone[1].Documentation/config/clone.txt +4
-0+ +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]Documentation/git-clone.txt +0
-0@@ -15,7 +15,7 @@ SYNOPSIS[--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
Documentation/git-clone.txt +1
-1- [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow][--filter=<filter>] [--] <repository>
[<directory>]Documentation/git-clone.txt +0
-1@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout::No checkout of HEAD is performed after the clone is complete.
+--[no-]reject-shallow::
Documentation/git-clone.txt +4
-1+ Fail if the source repository is a shallow repository. The + 'clone.rejectshallow' configuration variable can be used to + give the default. + --bare::Make a 'bare' Git repository. That is, instead of creating
<directory>and placing the administrativebuiltin/clone.c +22
-0@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow = -1; /* unspecified */ +static int config_shallow = -1; /* unspecified */static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) { + config_shallow =git_config_bool (k, v); + }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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) { + reject_shallow = config_shallow; + } +if (option_shallow !=-1 ) { + reject_shallow = option_shallow; + }/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values. @@ -1216,6 +1234,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die ("source repository is shallow, reject to clone." );if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;@@ -1227,6 +1247,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);fetch-pack.c +0
-0
fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1077
Quoted 7 lines
fetch-pack.c +4
-0@@ -1071,6 +1071,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->stateless_rpc)packet_flush (fd[1 ]); + +if (!args->deepen && args->remote_shallow) +die ("source repository is shallow, reject to clone." ); +
I am not sure if we should apply this to non-protocol-v2.
fetch-pack.c static void receive_shallow_info(struct fetch_pack_args *args, · line 1448
Quoted 9 lines
fetch-pack.c +2
-0if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL );@@ -1440,6 +1444,8 @@ static void receive_shallow_info(struct fetch_pack_args *args,* shallow. In v0, remote refs that reach these objects are * rejected (unless --update-shallow is set); do the same. */ +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." );
I just found that Johannes Schindelin wrote a document 14 year ago in Documentation/technical/shallow.txt:
"There are some unfinished ends of the whole shallow business:
A special handling of a shallow upstream is needed. At some stage, upload-pack has to check if it sends a shallow commit, and it should send that information early (or fail, if the client does not support shallow repositories). There is no support at all for this in this patch series."
It seems that my patch can sovle his worry in some degree, and maybe we could warn client in fetch-pack stage, if we don't choose to reject shallow cloning.
if (args->remote_shallow)
die("source repository is shallow, reject to clone.");
else
warning("remote source repository is shallow.");Quoted 186 lines
fetch-pack.c +0
-0prepare_shallow_info (si, shallows);if (si->nr_ours || si->nr_theirs)
alternate_shallow_file=fetch-pack.h +1
-0@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/* t/t5606-clone-options.sh +0
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=mainexport
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
test_expect_success'setup' 't/t5606-clone-options.sh +0
-0@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' ''
t/t5606-clone-options.sh +45
-0+test_expect_success 'fail to clone http shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +' + +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repo + +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' +
test_expect_success'uses "origin" for default remote name' 'git clone parent clone-default-origin &&
t/t5611-clone-config.sh +0
-0@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
test_cmpexpect actual
't/t5611-clone-config.sh +32
-0+test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' +
test_expect_successMINGW 'clone -c core.hideDotFiles' 'test_commitattributes .gitattributes "" &&
rm -rf child &&transport-helper.c +2
-1@@ -265,7 +265,8 @@ static const char *boolean_options[] = {TRANS_OPT_THIN ,TRANS_OPT_KEEP ,TRANS_OPT_FOLLOWTAGS , -TRANS_OPT_DEEPEN_RELATIVE +TRANS_OPT_DEEPEN_RELATIVE , +TRANS_OPT_REJECT_SHALLOW }; static int strbuf_set_helper_option(struct helper_data *data,transport.c +4
-0@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;transport.h +4
-0@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"base-commit:
225365fb5195e804274ab569ac3cc4919451dc7f--
gitgitgadget
Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
In reply to Junio C HamanoQuoted 6 lines
This may reject to clone from a shallow repository, but at this point the bulk of the tranfer from the origin repository has already happened, no? Rejecting after transferring many megabytes feels a bit too late. That is one of the reasons why I kept hinting that the transport layer needs to be taught an option to reject talking to a shallow counterpart if we want to add this feature [*1*].
Extending the transport layer in this way might not be too difficult in the case of native (SSH, git://) protocols and using protocol v0, since handshake() in transport.c (called indirectly from transport_get_remote_refs()) writes shallow information to a data structure that we could potentially expose for the caller to use (before it calls transport_fetch_refs(). I couldn't see how remote-using protocols (e.g. HTTP) communicate shallow information, though (remote-curl.c seems to just keep it for itself), so that will be a more difficult task. And of course there's the matter of protocol v2, which I discuss below.
Quoted 10 lines
[Footnote]
*1* Looking at
Documentation/technical/pack-protocol.txt, "git
fetch" seem to learn if the repository is shallow immediately upon contacting "upload-pack" during the Reference Discovery phase (we'd see 'shallow' packets if they are shallow). I suspect that the right solution would be to teach the codepath on the "git fetch" side that accepts, parses, and acts on this packet to optionally stop communication and error out when the caller asks not to talk with a shallow repository.
This is true with protocol v0, but protocol v2 bundles all shallow information (whether coming from the fact that the remote is shallow or the fact that the fetcher specified --depth etc.) and sends them together with the packfile. It may be possible to stop packfile download (saving bandwidth on the client side, at least) once such information is returned, though.
Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
Quoted 29 lines · Jonathan Tan
Quoted 6 lines
This may reject to clone from a shallow repository, but at this point the bulk of the tranfer from the origin repository has already happened, no? Rejecting after transferring many megabytes feels a bit too late. That is one of the reasons why I kept hinting that the transport layer needs to be taught an option to reject talking to a shallow counterpart if we want to add this feature [*1*].
Extending the transport layer in this way might not be too difficult in the case of native (SSH,
git://) protocols and using protocol v0, sincehandshake()intransport.c(called indirectly fromtransport_get_remote_refs()) writes shallow information to a data structure that we could potentially expose for the caller to use (before it callstransport_fetch_refs(). I couldn't see how remote-using protocols (e.g. HTTP) communicate shallow information, though (remote-curl.cseems to just keep it for itself), so that will be a more difficult task. And of course there's the matter of protocol v2, which I discuss below.Quoted 10 lines
[Footnote]
*1* Looking at
Documentation/technical/pack-protocol.txt, "git
fetch" seem to learn if the repository is shallow immediately upon contacting "upload-pack" during the Reference Discovery phase (we'd see 'shallow' packets if they are shallow). I suspect that the right solution would be to teach the codepath on the "git fetch" side that accepts, parses, and acts on this packet to optionally stop communication and error out when the caller asks not to talk with a shallow repository.
Quoted 6 lines
This is true with protocol v0, but protocol v2 bundles all shallow information (whether coming from the fact that the remote is shallow or the fact that the fetcher specified --depth etc.) and sends them together with the packfile. It may be possible to stop packfile download (saving bandwidth on the client side, at least) once such information is returned, though.
So in short, the "we do not want to clone from a shallow upstream" would not be possible to implement sensibly without significantly cleaning up the protocol layers first, which makes the whole thing pretty much moot.
Thanks for a review and insight.
Re: [PATCH v5] builtin/clone.c: add --reject-shallow option
In reply to [email protected]Hi,
Quoted 10 lines · On Mon, 1 Mar 2021, [email protected] wrote:
fetch-pack.c static void receive_shallow_info(struct fetch_pack_args *args, · line 1448
Quoted 6 lines
fetch-pack.c +2
-0@@ -1440,6 +1444,8 @@ static void receive_shallow_info(struct fetch_pack_args *args,* shallow. In v0, remote refs that reach these objects are * rejected (unless --update-shallow is set); do the same. */ +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." );I just found that Johannes Schindelin wrote a document 14 year ago in
Documentation/technical/shallow.txt:
Quoted 7 lines
"There are some unfinished ends of the whole shallow business:
A special handling of a shallow upstream is needed. At some stage, upload-pack has to check if it sends a shallow commit, and it should send that information early (or fail, if the client does not support shallow repositories). There is no support at all for this in this patch series."
Oh wow, what a blast from the past.
I do agree that your patch is an improvement over the current situation.
Thanks,
Johannes
Quoted 195 lines
It seems that my patch can sovle his worry in some degree, and maybe we could warn client in fetch-pack stage, if we don't choose to reject shallow cloning.
if (args->remote_shallow) die("source repository is shallow, reject to clone."); else warning("remote source repository is shallow.");Quoted 186 lines
fetch-pack.c +0
-0prepare_shallow_info (si, shallows);if (si->nr_ours || si->nr_theirs)
alternate_shallow_file=fetch-pack.h +1
-0@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/* t/t5606-clone-options.sh +0
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=mainexport
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
test_expect_success'setup' 't/t5606-clone-options.sh +0
-0@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' ''
t/t5606-clone-options.sh +45
-0+test_expect_success 'fail to clone http shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +' + +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repo + +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' +
test_expect_success'uses "origin" for default remote name' 'git clone parent clone-default-origin &&
t/t5611-clone-config.sh +0
-0@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
test_cmpexpect actual
't/t5611-clone-config.sh +32
-0+test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' +
test_expect_successMINGW 'clone -c core.hideDotFiles' 'test_commitattributes .gitattributes "" &&
rm -rf child &&transport-helper.c +2
-1@@ -265,7 +265,8 @@ static const char *boolean_options[] = {TRANS_OPT_THIN ,TRANS_OPT_KEEP ,TRANS_OPT_FOLLOWTAGS , -TRANS_OPT_DEEPEN_RELATIVE +TRANS_OPT_DEEPEN_RELATIVE , +TRANS_OPT_REJECT_SHALLOW }; static int strbuf_set_helper_option(struct helper_data *data,transport.c +4
-0@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;transport.h +4
-0@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"base-commit:
225365fb5195e804274ab569ac3cc4919451dc7f--
gitgitgadget
Re: Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
In reply to Jonathan Tan--------------
lilinchao
Quoted 7 lines
Quoted 6 lines
This may reject to clone from a shallow repository, but at this point the bulk of the tranfer from the origin repository has already happened, no? Rejecting after transferring many megabytes feels a bit too late. That is one of the reasons why I kept hinting that the transport layer needs to be taught an option to reject talking to a shallow counterpart if we want to add this feature [*1*].
Quoted 11 lines
Extending the transport layer in this way might not be too difficult in the case of native (SSH,
git://) protocols and using protocol v0, sincehandshake()intransport.c(called indirectly fromtransport_get_remote_refs()) writes shallow information to a data structure that we could potentially expose for the caller to use (before it callstransport_fetch_refs(). I couldn't see how remote-using protocols (e.g. HTTP) communicate shallow information, though (remote-curl.cseems to just keep it for itself), so that will be a more difficult task. And of course there's the matter of protocol v2, which I discuss below.
These discussions were based on PATCH_v4, which is quiet immature then, In the latest PATCH_v5, for the case of native protocols(ssh, git, file://), they will eventually call do_fetch_pack_v2() if it's protocol v2, and then will call receive_shallow_info() for the case FETCH_GET_PACK, so this is the place I made the change.
As for HTTPs protocl, as long as it's still smart protocol, which means do not fallback to dumb protocol, it will also call do_fetch_pack_v2(), and go to "check shallow info" trigger in receive_shallow_info().
So, base on PATCH_V5, I have tested protocol v2, which goes like this:
First, I created a shallow repo on gitlab and gitee respectively.
Then tried to clone them in my terminal, (in order not to look too verbose, I ommited the result when GIT_TRACE_PACKET is on).
$ ./git-clone --reject-shallow https://gitlab.com/Cactusinhand/rugged.git Cloning into 'rugged'... fatal: source repository is shallow, reject to clone.
$ ./git-clone --reject-shallow ssh://gitlab.com/Cactusinhand/rugged.git Cloning into 'rugged'... fatal: source repository is shallow, reject to clone.
$ ./git-clone --reject-shallow [email protected]:Cactusinhand/rugged.git Cloning into 'rugged'... fatal: source repository is shallow, reject to clone.
$ ./git-clone --reject-shallow https://gitee.com/cactusinhand/rugged.git Cloning into 'rugged'... fatal: source repository is shallow, reject to clone.
$ ./git-clone --reject-shallow ssh://gitee.com/cactusinhand/rugged.git Cloning into 'rugged'... fatal: source repository is shallow, reject to clone.
$ ./git-clone --reject-shallow [email protected]:cactusinhand/rugged.git Cloning into 'rugged'... fatal: source repository is shallow, reject to clone.
I haven't tested protocol v1, but I've made the change in do_fetch_pack(), which is for protocol version 0 and version 1.
I hope you can review the latest patch, and give me some suggestions.
Thanks!
Quoted 18 lines
Quoted 10 lines
[Footnote]
*1* Looking at
Documentation/technical/pack-protocol.txt, "git fetch" seem to learn if the repository is shallow immediately upon contacting "upload-pack" during the Reference Discovery phase (we'd see 'shallow' packets if they are shallow). I suspect that the right solution would be to teach the codepath on the "git fetch" side that accepts, parses, and acts on this packet to optionally stop communication and error out when the caller asks not to talk with a shallow repository.This is true with protocol v0, but protocol v2 bundles all shallow information (whether coming from the fact that the remote is shallow or the fact that the fetcher specified --depth etc.) and sends them together with the packfile. It may be possible to stop packfile download (saving bandwidth on the client side, at least) once such information is returned, though.
Re: [PATCH v5] builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetDocumentation/config/clone.txt clone.defaultRemoteName:: · line 8
Quoted 12 lines · Li Linchao via GitGitGadget
Documentation/config/clone.txt +4
-0@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Let's camelCase this, i.e. "clone.rejectShallow", as this file would be a good candidate to be the authoritative record of canonical spelling of these variables.
Documentation/config/clone.txt
Quoted 4 lines
+--[no-]reject-shallow::
Documentation/config/clone.txt +3
-0+ Fail if the source repository is a shallow repository. The + 'clone.rejectshallow' configuration variable can be used to + give the default.
Let's camelCase the reference to the variable, too. Also, typeset in monospace, i.e.
The clone.rejectShallow configuration variable ...
Documentation/config/clone.txt static int git_clone_config(const char *k, const char *v, void *cb) · line 867
Quoted 7 lines
Documentation/config/clone.txt +3
-0@@ -858,6 +862,9 @@ static int git_clone_config(const char *k, const char *v, void *cb) free(remote_name); remote_name = xstrdup(v); } + if (!strcmp(k, "clone.rejectshallow")) { + config_shallow = git_config_bool(k, v); + }
No need to use {} around a single-statement block, especially when the "if" statement does not have an "else" block.
The use of strcmp() against the variable name in all lowercase is correct here.
Quoted 4 lines
Documentation/config/clone.txt +0
-0@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix) */ git_config(git_clone_config, NULL);
Documentation/config/clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1176
Quoted 10 lines
Documentation/config/clone.txt +10
-0+ /* + * If option_shallow is specified from CLI option, + * ignore config_shallow from git_clone_config. + */ + if (config_shallow != -1) { + reject_shallow = config_shallow; + } + if (option_shallow != -1) { + reject_shallow = option_shallow; + }
Needless use of {} around single-statement blocks.
As reject_shallow is initialized to 0, this lets the option to be of the most priority, then the config (presumably coming from the per-user or per-system configuration), by without them, defaults to false. Good.
We'll have an extra git_config() call later, but that one will only read into config_shallow, never to be looked at because we will use reject_shallow variable anyway. OK.
Documentation/config/clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1238
Quoted 6 lines
Documentation/config/clone.txt +2
-0@@ -1216,6 +1234,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (filter_options.choice) warning(_("--filter is ignored in local clones; use file:// instead.")); if (!access(mkpath("%s/shallow", path), F_OK)) { + if (reject_shallow) + die("source repository is shallow, reject to clone.");
With the local transport, it (hopefully) is trivial to see if the source is shallow. OK.
Documentation/config/clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1254
Quoted 12 lines
Documentation/config/clone.txt +2
-0if (option_local > 0) warning(_("source repository is shallow, ignoring --local")); is_local = 0;@@ -1227,6 +1247,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_set_option(transport, TRANS_OPT_KEEP, "yes"); + if (reject_shallow) + transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1"); if (option_depth) transport_set_option(transport, TRANS_OPT_DEPTH, option_depth);
OK. What is really interesting will all happen inside the transport layer; the caller only has to ask for it.
The asymmetry with other options like "--depth" stands out and puzzles readers, though.
Do we really want to add the clone.rejectShallow configuration? After all, we do not give "clone.depth = 1" etc., and that is the reason why we only need "if (option_depth)" here in the near-by code.
I'd stop here for today, hoping that somebody much more familiar with the transport layer than I am will review and comment on the changes there.
Thanks.
Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
In reply to Jonathan TanQuoted 4 lines · Jonathan Tan
This is true with protocol v0, but protocol v2 bundles all shallow information (whether coming from the fact that the remote is shallow or the fact that the fetcher specified --depth etc.) and sends them together with the packfile.
By the above do you mean what happens in FETCH_GET_PACK arm where receive_shallow_info() is called when "shallow-info" header is seen, before the code continues to process wanted-refs, packfile-uris and then finally the packfile?
I do not think it makes much sense to ask any option to make us shallow (like --depth=<n>) while --reject-shallow is in use (after all, if the other side is deep enough to make us <n> commits deep, there is no reason to reject the other side as the source), so your "whether coming from the fact ..." part, while is a valid observation, can be ignored in practice (meaning: it is OK to make "--reject-shallow" be in effect only when we are trying to make a full clone, and reject combinations of it with --depth=<n> and such at the command parsing time).
Quoted 3 lines
It may be possible to stop packfile download (saving bandwidth on the client side, at least) once such information is returned, though.
Just like "upload-pack" does not get upset by a client that comes only for the initial refs advertisement and disconnects without asking for any "want" (aka "ls-remote"), the server side should be prepared to see if the other side cuts off after seeing the "shallow-info" section header or after seeing the the whole "shallow-info" section, so we should be able to leave early without having to download the bulk data. If the "upload-pack" spends unnecessary cycles when it happens, then we need to fix that. Even if the "fetch" client does not willingly disconnect in the middle, the network disconnect may happen at any point in the exchange, and we'd need to be prepared for it.
Do we need to read and parse the "shallow-info" section, or would the mere presense of the section mean the other side knows this side needs to futz with the .git/shallow information (either because we asked to be made shallow with --depth and the like, or because we tried to clone from them and they are shallow)?
Thanks.
Re: [PATCH v4] builtin/clone.c: add --reject-shallow option
Quoted 11 lines
Quoted 4 lines · Jonathan Tan
This is true with protocol v0, but protocol v2 bundles all shallow information (whether coming from the fact that the remote is shallow or the fact that the fetcher specified --depth etc.) and sends them together with the packfile.
By the above do you mean what happens in
FETCH_GET_PACKarm wherereceive_shallow_info()is called when "shallow-info" header is seen, before the code continues to process wanted-refs, packfile-uris and then finally the packfile?
Yes.
Quoted 26 lines
I do not think it makes much sense to ask any option to make us shallow (like --depth=<n>) while --reject-shallow is in use (after all, if the other side is deep enough to make us <n> commits deep, there is no reason to reject the other side as the source), so your "whether coming from the fact ..." part, while is a valid observation, can be ignored in practice (meaning: it is OK to make "--reject-shallow" be in effect only when we are trying to make a full clone, and reject combinations of it with --depth=<n> and such at the command parsing time).
Quoted 3 lines
It may be possible to stop packfile download (saving bandwidth on the client side, at least) once such information is returned, though.
Just like "upload-pack" does not get upset by a client that comes only for the initial refs advertisement and disconnects without asking for any "want" (aka "ls-remote"), the server side should be prepared to see if the other side cuts off after seeing the "shallow-info" section header or after seeing the the whole "shallow-info" section, so we should be able to leave early without having to download the bulk data. If the "upload-pack" spends unnecessary cycles when it happens, then we need to fix that. Even if the "fetch" client does not willingly disconnect in the middle, the network disconnect may happen at any point in the exchange, and we'd need to be prepared for it.
Quoted 5 lines
Do we need to read and parse the "shallow-info" section, or would the mere presense of the section mean the other side knows this side needs to futz with the .git/shallow information (either because we asked to be made shallow with --depth and the like, or because we tried to clone from them and they are shallow)?
Reading the documentation, the mere presence should be enough. Yes, I think upload-pack will spend unnecessary cycles if the channel is terminated halfway (and I don't know if we can prevent spending these cycles, since I/O can be buffered). I think it should be possible for the client to cut off when it sees shallow-info (besides the possible wastage of cycles and I/O on the server's end).
Having said that, I think this different from the ls-remote case. There, the server is awaiting another request from the user before sending more information, but here, the server intends to send everything at once.
Re: Re: [PATCH v5] builtin/clone.c: add --reject-shallow option
In reply to Junio C HamanoQuoted 19 lines
Documentation/config/clone.txt clone.defaultRemoteName:: · line 8
Quoted 12 lines · Li Linchao via GitGitGadget
Documentation/config/clone.txt +0
-0@@ -2,3 +2,7 @@ clone.defaultRemoteName::The name of the remote to create when cloning a repository. Defaults to
origin, and can be overridden by passing the--origincommand-line option to linkgit:git-clone[1].Documentation/config/clone.txt +4
-0+ +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]Let's camelCase this, i.e. "clone.rejectShallow", as this file would be a good candidate to be the authoritative record of canonical spelling of these variables.
Quoted 1 line
OK,thanks for reminding this.
Quoted 76 lines
Documentation/config/clone.txt
Quoted 5 lines
+--[no-]reject-shallow::
Documentation/config/clone.txt +3
-0+ Fail if the source repository is a shallow repository. The + 'clone.rejectshallow' configuration variable can be used to + give the default.Let's camelCase the reference to the variable, too. Also, typeset in monospace, i.e.
The
clone.rejectShallowconfiguration variable ...Documentation/config/clone.txt static int git_clone_config(const char *k, const char *v, void *cb) · line 867
Quoted 7 lines
Documentation/config/clone.txt +3
-0@@ -858,6 +862,9 @@ static int git_clone_config(const char *k, const char *v, void *cb) free(remote_name); remote_name = xstrdup(v); } + if (!strcmp(k, "clone.rejectshallow")) { + config_shallow = git_config_bool(k, v); + }No need to use {} around a single-statement block, especially when the "if" statement does not have an "else" block.
The use of
strcmp()against the variable name in all lowercase is correct here.Quoted 4 lines
Documentation/config/clone.txt +0
-0@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix) */ git_config(git_clone_config, NULL);Documentation/config/clone.txt
Quoted 10 lines
Documentation/config/clone.txt +10
-0+ /* + * If option_shallow is specified from CLI option, + * ignore config_shallow from git_clone_config. + */ + if (config_shallow != -1) { + reject_shallow = config_shallow; + } + if (option_shallow != -1) { + reject_shallow = option_shallow; + }Needless use of {} around single-statement blocks.
As
reject_shallowis initialized to 0, this lets the option to be of the most priority, then the config (presumably coming from the per-user or per-system configuration), by without them, defaults to false. Good.We'll have an extra
git_config()call later, but that one will only read intoconfig_shallow, never to be looked at because we will usereject_shallowvariable anyway. OK.Documentation/config/clone.txt int cmd_clone(int argc, const char **argv, const char *prefix) · line 1238
Quoted 6 lines
Documentation/config/clone.txt +2
-0@@ -1216,6 +1234,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (filter_options.choice) warning(_("--filter is ignored in local clones; use file:// instead.")); if (!access(mkpath("%s/shallow", path), F_OK)) { + if (reject_shallow) + die("source repository is shallow, reject to clone.");With the local transport, it (hopefully) is trivial to see if the source is shallow. OK.
Quoted 9 lines
Documentation/config/clone.txt +0
-0if (option_local > 0) warning(_("source repository is shallow, ignoring --local")); is_local = 0;@@ -1227,6 +1247,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
transport_set_option(transport, TRANS_OPT_KEEP, "yes");Documentation/config/clone.txt +2
-0+ if (reject_shallow) + transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");Quoted 3 lines
if (
option_depth)transport_set_option(transport, TRANS_OPT_DEPTH, option_depth);OK. What is really interesting will all happen inside the transport layer; the caller only has to ask for it.
Quoted 3 lines
The asymmetry with other options like "--depth" stands out and puzzles readers, though.
True, but since reject_shallow is not just an option from CLI, so I think we can't just call it "option_shallow" here to order to keep symmetry with other options below.
Quoted 1 line
Do we really want to add the clone.rejectShallow configuration?
Only when I want all my git clone in my machine can avoid cloning shallow repo, and no need to provide the option "--reject-shallow" every time, then this configuration would make sense.
Quoted 10 lines
After all, we do not give "clone.depth = 1" etc., and that is the reason why we only need "if (
option_depth)" here in the near-by code.I'd stop here for today, hoping that somebody much more familiar with the transport layer than I am will review and comment on the changes there.
Thanks.
Re: Re: [PATCH v5] builtin/clone.c: add --reject-shallow option
In reply to Johannes SchindelinQuoted 22 lines
Hi,
Quoted 10 lines · On Mon, 1 Mar 2021, [email protected] wrote:
fetch-pack.c static void receive_shallow_info(struct fetch_pack_args *args, · line 1448
Quoted 6 lines
fetch-pack.c +2
-0@@ -1440,6 +1444,8 @@ static void receive_shallow_info(struct fetch_pack_args *args,* shallow. In v0, remote refs that reach these objects are * rejected (unless --update-shallow is set); do the same. */ +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." );I just found that Johannes Schindelin wrote a document 14 year ago in
Documentation/technical/shallow.txt:Quoted 7 lines
"There are some unfinished ends of the whole shallow business:
A special handling of a shallow upstream is needed. At some stage, upload-pack has to check if it sends a shallow commit, and it should send that information early (or fail, if the client does not support shallow repositories). There is no support at all for this in this patch series."
Quoted 4 lines
Oh wow, what a blast from the past.
I do agree that your patch is an improvement over the current situation.
Thanks. Glad to hear the voice from you, hope I can get some suggestions from you too, especially on the transport part.
Quoted 12 lines
Thanks,
JohannesQuoted 9 lines
It seems that my patch can sovle his worry in some degree, and maybe we could warn client in fetch-pack stage, if we don't choose to reject shallow cloning.
if (
args->remote_shallow)die("source repository is shallow, reject to clone."); elsewarning("remote source repository is shallow.");
PATCH v6 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Changes since v5:
* camelcase config variable
* warning client that source repo is shallow
* better support ssh:// and git:// protocol v1, v2
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v5:
1: 3f765e49e4a7 ! 1: 953122588ca8 builtin/clone.c: add --reject-shallow option
@@ Documentation/config/clone.txt: clone.defaultRemoteName::
`origin`, and can be overridden by passing the `--origin` command-line
option to linkgit:git-clone[1].
+
-+clone.rejectshallow::
++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]
@@ Documentation/git-clone.txt: objects from the source repository into a pack in t
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
++ Fail if the source repository is a shallow repository.
++ The 'clone.rejectShallow' configuration variable can be used to
+ give the default.
+
--bare::
@@ builtin/clone.c: static int git_clone_config(const char *k, const char *v, void
free(remote_name);
remote_name = xstrdup(v);
}
-+ if (!strcmp(k, "clone.rejectshallow")) {
++ if (!strcmp(k, "clone.rejectshallow"))
+ config_shallow = git_config_bool(k, v);
-+ }
++
return git_default_config(k, v, cb);
}
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
+ * If option_shallow is specified from CLI option,
+ * ignore config_shallow from git_clone_config.
+ */
-+ if (config_shallow != -1) {
++ if (config_shallow != -1)
+ reject_shallow = config_shallow;
-+ }
-+ if (option_shallow != -1) {
++
++ if (option_shallow != -1)
+ reject_shallow = option_shallow;
-+ }
++
/*
* apply the remote name provided by --origin only after this second
* call to git_config, to ensure it overrides all config-based values.
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
if (!access(mkpath("%s/shallow", path), F_OK)) {
+ if (reject_shallow)
+ die("source repository is shallow, reject to clone.");
++ else
++ warning("source repository is shallow.");
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
@@ fetch-pack.c: static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (args->stateless_rpc)
packet_flush(fd[1]);
-+
-+ if (!args->deepen && args->remote_shallow)
-+ die("source repository is shallow, reject to clone.");
+
if (args->deepen)
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
NULL);
+- else if (si->nr_ours || si->nr_theirs)
++ else if (si->nr_ours || si->nr_theirs) {
++ if (args->remote_shallow)
++ die("source repository is shallow, reject to clone.");
++ else
++ warning("source repository is shallow.");
+ alternate_shallow_file = setup_temporary_shallow(si->shallow);
+- else
++ } else
+ alternate_shallow_file = NULL;
+ if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
+ &gitmodules_oids))
@@ fetch-pack.c: static void receive_shallow_info(struct fetch_pack_args *args,
- * shallow. In v0, remote refs that reach these objects are
* rejected (unless --update-shallow is set); do the same.
*/
-+ if (args->remote_shallow)
-+ die("source repository is shallow, reject to clone.");
prepare_shallow_info(si, shallows);
- if (si->nr_ours || si->nr_theirs)
+- if (si->nr_ours || si->nr_theirs)
++ if (si->nr_ours || si->nr_theirs) {
++ if (args->remote_shallow)
++ die("source repository is shallow, reject to clone.");
++ else
++ warning("source repository is shallow.");
alternate_shallow_file =
+ setup_temporary_shallow(si->shallow);
+- else
++ } else
+ alternate_shallow_file = NULL;
+ } else {
+ alternate_shallow_file = NULL;
## fetch-pack.h ##
@@ fetch-pack.h: struct fetch_pack_args {
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
test_commit attributes .gitattributes "" &&
rm -rf child &&
- ## transport-helper.c ##
-@@ transport-helper.c: static const char *boolean_options[] = {
- TRANS_OPT_THIN,
- TRANS_OPT_KEEP,
- TRANS_OPT_FOLLOWTAGS,
-- TRANS_OPT_DEEPEN_RELATIVE
-+ TRANS_OPT_DEEPEN_RELATIVE,
-+ TRANS_OPT_REJECT_SHALLOW
- };
-
- static int strbuf_set_helper_option(struct helper_data *data,
-
## transport.c ##
@@ transport.c: static int set_git_option(struct git_transport_options *opts,
list_objects_filter_die_if_populated(&opts->filter_options);
@@ transport.h: void transport_check_allowed(const char *type);
/* Aggressively fetch annotated tags if possible */
#define TRANS_OPT_FOLLOWTAGS "followtags"
-+/* reject shallow repo transport */
++/* Reject shallow repo transport */
+#define TRANS_OPT_REJECT_SHALLOW "rejectshallow"
+
/* Accept refs that may update .git/shallow without --depth */Documentation/config/clone.txt | 4 +++ Documentation/git-clone.txt | 7 ++++- builtin/clone.c | 24 +++++++++++++++++ fetch-pack.c | 17 +++++++++--- fetch-pack.h | 1 + t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ transport.c | 4 +++ transport.h | 4 +++ 9 files changed, 135 insertions(+), 5 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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 + give the default. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +24 -0
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) + config_shallow =git_config_bool (k, v); +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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) + reject_shallow = config_shallow; + +if (option_shallow !=-1 ) + reject_shallow = option_shallow; +/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values.
@@ -1216,6 +1234,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die ("source repository is shallow, reject to clone." ); +else +warning ("source repository is shallow." );if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1227,6 +1249,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);
fetch-pack.c +13 -4
@@ -1126,12 +1126,17 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->stateless_rpc)packet_flush (fd[1 ]); +if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL ); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." ); +else +warning ("source repository is shallow." ); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &gitmodules_oids))
@@ -1498,10 +1503,14 @@ static void receive_shallow_info(struct fetch_pack_args *args,* rejected (unless --update-shallow is set); do the same. */ prepare_shallow_info (si, shallows); -if (si->nr_ours || si->nr_theirs) +if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." ); +else +warning ("source repository is shallow." ); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ; }else { alternate_shallow_file =NULL ;
fetch-pack.h +1 -0
@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/*
t/t5606-clone-options.sh +47 -0
59 lines not on this page · raw message
t/t5611-clone-config.sh +32 -0
@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
transport.c +4 -0
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;
transport.h +4 -0
@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* Reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
base-commit: f01623b2c9d14207e497b21ebc6b3ec4afaf4b46
Signature · 1 line
gitgitgadget
Re: [PATCH v6] builtin/clone.c: add --reject-shallow option
PING.
Seems that this patch have been forgotten by everyone.
--------------
Quoted 528 lines
From: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
Signed-off-by lilinchao <[email protected]>---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Changes since v5:
* camelcase config variable
* warning client that source repo is shallow
* better support ssh:// andgit://protocol v1, v2Signed-off-by lilinchao [email protected]Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/865Range-diff vs v5:
1:
3f765e49e4a7! 1:953122588ca8builtin/clone.c: add --reject-shallow option @@Documentation/config/clone.txt: clone.defaultRemoteName::
origin, and can be overridden by passing the--origincommand-line option to linkgit:git-clone[1].
+
-+clone.rejectshallow::
++clone.rejectShallow::
+ Reject to clone a repository if it is a shallow one, can be overridden by
+ passing option--reject-shallowin command line. See linkgit:git-clone[1]
@@Documentation/git-clone.txt: objects from the source repository into a pack in t 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
++ Fail if the source repository is a shallow repository.
++ The 'clone.rejectShallow' configuration variable can be used to
+ give the default.
+
--bare::
@@builtin/clone.c: static int git_clone_config(const char *k, const char *v, voidfree(remote_name);
remote_name= xstrdup(v);
}
-+ if (!strcmp(k, "clone.rejectshallow")) {
++ if (!strcmp(k, "clone.rejectshallow"))
+config_shallow=git_config_bool(k, v);
-+ }
++
returngit_default_config(k, v, cb);
}
@@builtin/clone.c: intcmd_clone(int argc, const char **argv, const char *prefix)
+ * Ifoption_shallowis specified from CLI option,
+ * ignoreconfig_shallowfromgit_clone_config.
+ */
-+ if (config_shallow!= -1) {
++ if (config_shallow!= -1)
+reject_shallow=config_shallow;
-+ }
-+ if (option_shallow!= -1) {
++
++ if (option_shallow!= -1)
+reject_shallow=option_shallow;
-+ }
++
/*
* apply the remote name provided by --origin only after this second
* call togit_config, to ensure it overrides all config-based values. @@builtin/clone.c: intcmd_clone(int argc, const char **argv, const char *prefix)if (!access(mkpath("%s/shallow", path),F_OK)) {
+ if (reject_shallow)
+die("source repository is shallow, reject to clone.");
++ else
++warning("source repository is shallow.");
if (option_local> 0)
warning(_("source repository is shallow, ignoring --local"));is_local= 0;
@@fetch-pack.c: static struct ref *do_fetch_pack(structfetch_pack_args*args,
if (args->stateless_rpc)
packet_flush(fd[1]);
-+
-+ if (!args->deepen &&args->remote_shallow)
-+die("source repository is shallow, reject to clone.");
+
if (args->deepen)
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL);+- else if (si->nr_ours || si->nr_theirs) ++ else if (si->nr_ours || si->nr_theirs) {++ if (
args->remote_shallow)
++die("source repository is shallow, reject to clone.");
++ else
++warning("source repository is shallow.");
+alternate_shallow_file=setup_temporary_shallow(si->shallow);
+- else
++ } else
+alternate_shallow_file= NULL;
+ if (get_pack(args, fd,pack_lockfiles, NULL, sought,nr_sought,
+&gitmodules_oids))
@@fetch-pack.c: static void receive_shallow_info(structfetch_pack_args*args,
- * shallow. In v0, remote refs that reach these objects are
* rejected (unless --update-shallow is set); do the same.
*/
-+ if (args->remote_shallow)
-+die("source repository is shallow, reject to clone.");
prepare_shallow_info(si, shallows);- if (si->nr_ours || si->nr_theirs) +- if (si->nr_ours || si->nr_theirs) ++ if (si->nr_ours || si->nr_theirs) {++ if (
args->remote_shallow)
++die("source repository is shallow, reject to clone.");
++ else
++warning("source repository is shallow.");
alternate_shallow_file=
+setup_temporary_shallow(si->shallow);
+- else
++ } else
+alternate_shallow_file= NULL;
+ } else {
+alternate_shallow_file= NULL;
##fetch-pack.h##
@@fetch-pack.h: structfetch_pack_args{
@@t/t5611-clone-config.sh:test_expect_success'clone -c remote.<remote>.fetch=<retest_commitattributes .gitattributes "" &&
rm -rf child &&
- ##transport-helper.c##
-@@transport-helper.c: static const char *boolean_options[] = {
-TRANS_OPT_THIN,
-TRANS_OPT_KEEP,
-TRANS_OPT_FOLLOWTAGS,
--TRANS_OPT_DEEPEN_RELATIVE
-+TRANS_OPT_DEEPEN_RELATIVE,
-+TRANS_OPT_REJECT_SHALLOW
- };
-
- static int strbuf_set_helper_option(structhelper_data*data,
-
##transport.c##
@@transport.c: static int set_git_option(structgit_transport_options*opts,list_objects_filter_die_if_populated(&opts->filter_options);
@@transport.h: voidtransport_check_allowed(const char *type);
/* Aggressively fetch annotated tags if possible */
#defineTRANS_OPT_FOLLOWTAGS"followtags"
-+/* reject shallow repo transport */
++/* Reject shallow repo transport */
+#defineTRANS_OPT_REJECT_SHALLOW"rejectshallow"
+
/* Accept refs that may update .git/shallow without --depth */
Documentation/config/clone.txt| 4 +++ Documentation/git-clone.txt | 7 ++++-
builtin/clone.c | 24 +++++++++++++++++ fetch-pack.c | 17 +++++++++--- fetch-pack.h | 1 + t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ transport.c | 4 +++
transport.h | 4 +++9 files changed, 135 insertions(+), 5 deletions(-)Documentation/config/clone.txt +0
-0@@ -2,3 +2,7 @@ clone.defaultRemoteName::The name of the remote to create when cloning a repository. Defaults to
origin, and can be overridden by passing the--origincommand-line option to linkgit:git-clone[1].Documentation/config/clone.txt +4
-0+ +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]Documentation/git-clone.txt +0
-0@@ -15,7 +15,7 @@ SYNOPSIS[--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
Documentation/git-clone.txt +1
-1- [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow][--filter=<filter>] [--] <repository>
[<directory>]Documentation/git-clone.txt +0
-1@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout::No checkout of HEAD is performed after the clone is complete.
+--[no-]reject-shallow::
Documentation/git-clone.txt +4
-1+ Fail if the source repository is a shallow repository. + The 'clone.rejectShallow' configuration variable can be used to + give the default. + --bare::Make a 'bare' Git repository. That is, instead of creating
<directory>and placing the administrativebuiltin/clone.c +24
-0@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow = -1; /* unspecified */ +static int config_shallow = -1; /* unspecified */static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) + config_shallow =git_config_bool (k, v); +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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) + reject_shallow = config_shallow; + +if (option_shallow !=-1 ) + reject_shallow = option_shallow; +/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values. @@ -1216,6 +1234,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die ("source repository is shallow, reject to clone." ); +else +warning ("source repository is shallow." );if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;@@ -1227,6 +1249,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);fetch-pack.c +12
-3@@ -1126,12 +1126,17 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->stateless_rpc)packet_flush (fd[1 ]); +if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL ); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." ); +else +warning ("source repository is shallow." ); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &gitmodules_oids))@@ -1498,10 +1503,14 @@ static void receive_shallow_info(struct fetch_pack_args *args,* rejected (unless --update-shallow is set); do the same. */ prepare_shallow_info (si, shallows); -if (si->nr_ours || si->nr_theirs) +if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die ("source repository is shallow, reject to clone." ); +else +warning ("source repository is shallow." );
alternate_shallow_file=setup_temporary_shallow(si->shallow);fetch-pack.c +1
-1-else + }else
alternate_shallow_file= NULL;
} else {alternate_shallow_file= NULL;fetch-pack.h +1
-0@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/* t/t5606-clone-options.sh +0
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=mainexport
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
test_expect_success'setup' 't/t5606-clone-options.sh +0
-0@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' ''
t/t5606-clone-options.sh +45
-0+test_expect_success 'fail to clone http shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'fail to clone non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +' + +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repo + +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' +
test_expect_success'uses "origin" for default remote name' 'git clone parent clone-default-origin &&
t/t5611-clone-config.sh +0
-0@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
test_cmpexpect actual
't/t5611-clone-config.sh +32
-0+test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' +
test_expect_successMINGW 'clone -c core.hideDotFiles' 'test_commitattributes .gitattributes "" &&
rm -rf child &&transport.c +4
-0@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;transport.h +4
-0@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* Reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"base-commit:
f01623b2c9d14207e497b21ebc6b3ec4afaf4b46--
gitgitgadget
PATCH v7 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Changes since v5:
* camelcase config variable
* warning client that source repo is shallow
* better support ssh:// and git:// protocol v1, v2
Changes since v6:
* use _() for warning/die statement
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v7
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v7
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v6:
1: 953122588ca8 ! 1: b957b77bfd79 builtin/clone.c: add --reject-shallow option
@@ Commit message
Signed-off-by: lilinchao <[email protected]>
+ Reviewed-by: Derrick Stolee <[email protected]>
+ Reviewed-by: Junio C Hamano<[email protected]>
+ Reviewed-by: Johannes Schindelin <[email protected]>
+ Reviewed-by: Jonathan Tan<[email protected]>
+
## Documentation/config/clone.txt ##
@@ Documentation/config/clone.txt: clone.defaultRemoteName::
The name of the remote to create when cloning a repository. Defaults to
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
warning(_("--filter is ignored in local clones; use file:// instead."));
if (!access(mkpath("%s/shallow", path), F_OK)) {
+ if (reject_shallow)
-+ die("source repository is shallow, reject to clone.");
++ die(_("source repository is shallow, reject to clone."));
+ else
-+ warning("source repository is shallow.");
++ warning(_("source repository is shallow."));
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
## fetch-pack.c ##
@@ fetch-pack.c: static struct ref *do_fetch_pack(struct fetch_pack_args *args,
-
- if (args->stateless_rpc)
- packet_flush(fd[1]);
-+
if (args->deepen)
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
NULL);
- else if (si->nr_ours || si->nr_theirs)
+ else if (si->nr_ours || si->nr_theirs) {
+ if (args->remote_shallow)
-+ die("source repository is shallow, reject to clone.");
++ die(_("source repository is shallow, reject to clone."));
+ else
-+ warning("source repository is shallow.");
++ warning(_("source repository is shallow."));
alternate_shallow_file = setup_temporary_shallow(si->shallow);
- else
+ } else
@@ fetch-pack.c: static void receive_shallow_info(struct fetch_pack_args *args,
- if (si->nr_ours || si->nr_theirs)
+ if (si->nr_ours || si->nr_theirs) {
+ if (args->remote_shallow)
-+ die("source repository is shallow, reject to clone.");
++ die(_("source repository is shallow, reject to clone."));
+ else
-+ warning("source repository is shallow.");
++ warning(_("source repository is shallow."));
alternate_shallow_file =
setup_temporary_shallow(si->shallow);
- elseDocumentation/config/clone.txt | 4 +++ Documentation/git-clone.txt | 7 ++++- builtin/clone.c | 24 +++++++++++++++++ fetch-pack.c | 16 +++++++++--- fetch-pack.h | 1 + t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ transport.c | 4 +++ transport.h | 4 +++ 9 files changed, 134 insertions(+), 5 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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 + give the default. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +24 -0
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) + config_shallow =git_config_bool (k, v); +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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) + reject_shallow = config_shallow; + +if (option_shallow !=-1 ) + reject_shallow = option_shallow; +/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values.
@@ -1216,6 +1234,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." ));if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1227,6 +1249,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);
fetch-pack.c +12 -4
@@ -1129,9 +1129,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL ); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." )); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &gitmodules_oids))
@@ -1498,10 +1502,14 @@ static void receive_shallow_info(struct fetch_pack_args *args,* rejected (unless --update-shallow is set); do the same. */ prepare_shallow_info (si, shallows); -if (si->nr_ours || si->nr_theirs) +if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." )); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ; }else { alternate_shallow_file =NULL ;
fetch-pack.h +1 -0
@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/*
t/t5606-clone-options.sh +47 -0
59 lines not on this page · raw message
t/t5611-clone-config.sh +32 -0
@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should fail to clone' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
transport.c +4 -0
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;
transport.h +4 -0
@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* Reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
base-commit: 9198c13e34f6d51c983b31a9397d4d62bc2147ac
Signature · 1 line
gitgitgadget
Re: [PATCH v7] builtin/clone.c: add --reject-shallow option
Quoted 10 lines · Li Linchao via GitGitGadget
...
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.Signed-off-by lilinchao <[email protected]>Reviewed-by Derrick Stolee <[email protected]>Reviewed-by Junio C Hamano<[email protected]>Reviewed-by Johannes Schindelin <[email protected]>Reviewed-by Jonathan Tan<[email protected]>
The Reviewed-by trailer means something quite different from what you seem to think here. It is only given by the reviewers to the patch when they carefully reviewed and agrees what is in the patch. The patch authors are in no position to add it, unless they are explicitly told by reviewers that "this patch now can have my Reviewed-by:" or some equivalent.
The (ideal) flow of events is
0. The author comes up with an idea and writes a patch.
1. The patch is sent to the list and Cc'ed to people who may be familiar with the area the patch touches. For second and subsequent iterations, those who gave review comments to the previous iterations are also good people to Cc to.
2. People give comments as reponses to the patch.
(a) some may be happy with the iteration of the patch they reviewed, and may say "Thanks for contributing, this is now
Reviewed-by: me". For second and subsequent iterations, they may say "This was improved relative to the previous iteration, and it still looks good and you have my Reviewed-by:".
(b) some may give constructive criticism, alternatives, enhancements, or outright "not a good idea, don't do this because ...".
(c) some may just act as cheerleaders.
3. The author thinks about the review comments and also may find improvement him/herself.
(a) There may need an update to the patch. If the patch has changed since the previous version in any way, ignore
Reviewed-by: received in 2-(a). When a significant help was given to update the patch, you may add "Helped-by:" trailer to credit the person's contribution.
Your own "Signed-off-by:" appears the last in the trailers (i.e. "this iteration of the patch was written with help from these people, and then I am signing it off just before sending it out").
Go back to 1. and repeat as many times as it takes.
(b) There may not be a need for any update to the patch. Only add the Reviewed-by: received in 2-(a) and otherwise do not change anything. Your own "Signed-off-by:" appears the last in the trailers. Send it to the list and to the maintainer (me).
4. The maintainer applies the patch, unless there is no other comments received on that supposedly-the-final version sent in 3-(b), but a late review comment may make us realize that it was premature, in which case we may go back to 3-(a).
Re: [PATCH v7] builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetbuiltin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1240
Quoted 8 lines · Li Linchao via GitGitGadget
builtin/clone.c +4
-0@@ -1216,6 +1234,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." ));
Hmph, is it an improvement to warn() when the user does not mind cloning a shallow repository?
$ git clone --depth=3 $URL clone-1 $ git clone file://$(pwd)/clone-1 clone-2
would give us clone-2 that is just as functional as clone-1 is, no? clone-1 may be missing objects that is needed far into the past, and clone-2 would lack the same set of objects as clone-1 does, but a user who is happily using clone-1 would be happy with clone-2 the same way, no?
fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1134
Quoted 12 lines
fetch-pack.c +3
-1@@ -1129,9 +1129,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL ); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." ));
Stopping early before calling get_pack() would significantly reduce the overhead, which is good.
fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1136
Quoted 2 lines
fetch-pack.c +2
-0+else +warning (_ ("source repository is shallow." ));
The same question on the wisdom of warning here.
fetch-pack.c static void receive_shallow_info(struct fetch_pack_args *args, · line 1509
Quoted 10 lines
fetch-pack.c +5
-1@@ -1498,10 +1502,14 @@ static void receive_shallow_info(struct fetch_pack_args *args,* rejected (unless --update-shallow is set); do the same. */ prepare_shallow_info (si, shallows); -if (si->nr_ours || si->nr_theirs) +if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." ));
OK, so, this is the equivalent of the above for protocol-v2? The same comments apply, then.
Quoted 14 lines
t/t5606-clone-options.sh +2
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpd test_expect_success 'setup' '
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 50
Quoted 4 lines
t/t5606-clone-options.sh +1
-0@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' ' +test_expect_success 'fail to clone http shallow repository' '
s/fail to clone/reject cloning/, perhaps.
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 77
Quoted 4 lines
t/t5606-clone-options.sh +4
-0+test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo
OK. Also without "--no-reject-shallow" option, the command would successfully clone from the shallow-repo, I presume?
The changes look more-or-less good to me, except for the "warning()" bit, which I do not think is a good idea.
Re: Re: [PATCH v7] builtin/clone.c: add --reject-shallow option
In reply to a message not in the archive--------------
[email protected]
Quoted 66 lines
Quoted 10 lines · Li Linchao via GitGitGadget
...
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.Signed-off-by lilinchao <[email protected]>Reviewed-by Derrick Stolee <[email protected]>Reviewed-by Junio C Hamano<[email protected]>Reviewed-by Johannes Schindelin <[email protected]>Reviewed-by Jonathan Tan<[email protected]>The Reviewed-by trailer means something quite different from what you seem to think here. It is only given by the reviewers to the patch when they carefully reviewed and agrees what is in the patch. The patch authors are in no position to add it, unless they are explicitly told by reviewers that "this patch now can have my Reviewed-by:" or some equivalent.
The (ideal) flow of events is
0. The author comes up with an idea and writes a patch.
1. The patch is sent to the list and Cc'ed to people who may be familiar with the area the patch touches. For second and subsequent iterations, those who gave review comments to the previous iterations are also good people to Cc to.
2. People give comments as reponses to the patch.
(a) some may be happy with the iteration of the patch they reviewed, and may say "Thanks for contributing, this is now
Reviewed-by: me". For second and subsequent iterations, they may say "This was improved relative to the previous iteration, and it still looks good and you have my Reviewed-by:".(b) some may give constructive criticism, alternatives, enhancements, or outright "not a good idea, don't do this because ...".
(c) some may just act as cheerleaders.
3. The author thinks about the review comments and also may find improvement him/herself.
(a) There may need an update to the patch. If the patch has changed since the previous version in any way, ignore
Reviewed-by: received in 2-(a). When a significant help was given to update the patch, you may add "Helped-by:" trailer to credit the person's contribution.Your own "Signed-off-by:" appears the last in the trailers (i.e. "this iteration of the patch was written with help from these people, and then I am signing it off just before sending it out").
Go back to 1. and repeat as many times as it takes.
(b) There may not be a need for any update to the patch. Only add the Reviewed-by: received in 2-(a) and otherwise do not change anything. Your own "Signed-off-by:" appears the last in the trailers. Send it to the list and to the maintainer (me).
Quoted 5 lines
4. The maintainer applies the patch, unless there is no other comments received on that supposedly-the-final version sent in 3-(b), but a late review comment may make us realize that it was premature, in which case we may go back to 3-(a).
Many thanks for so detailed instructions about work flow in git community. I will follow this flow tightly.
Re: Re: [PATCH v7] builtin/clone.c: add --reject-shallow option
In reply to a message not in the archiveThanks for your review.
--------------
[email protected]
Quoted 14 lines
builtin/clone.c int cmd_clone(int argc, const char **argv, const char *prefix) · line 1240
Quoted 8 lines · Li Linchao via GitGitGadget
builtin/clone.c +4
-0@@ -1216,6 +1234,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (filter_options.choice) warning(_("--filter is ignored in local clones; use file:// instead.")); if (!access(mkpath("%s/shallow", path), F_OK)) { +if (reject_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." ));Hmph, is it an improvement to
warn()when the user does not mind cloning a shallow repository?
Uh, the idea to warn comes from previous comments I wrote 25 days ago:
"and maybe we could warn client in fetch-pack stage, if we don't choose to reject shallow cloning."
then no one response to that point, so I think is ok to apply it. Now, it seems like a bad idea. I will remove it.
Quoted 30 lines
$ git clone --depth=3 $URL clone-1 $ git clone file://$(pwd)/clone-1 clone-2would give us clone-2 that is just as functional as clone-1 is, no? clone-1 may be missing objects that is needed far into the past, and clone-2 would lack the same set of objects as clone-1 does, but a user who is happily using clone-1 would be happy with clone-2 the same way, no?
fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1134
Quoted 12 lines
fetch-pack.c +3
-1@@ -1129,9 +1129,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, if (args->deepen) setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." ));Stopping early before calling
get_pack()would significantly reduce the overhead, which is good.fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1136
Quoted 2 lines
fetch-pack.c +2
-0+else +warning (_ ("source repository is shallow." ));The same question on the wisdom of warning here.
Quoted 13 lines
fetch-pack.c static void receive_shallow_info(struct fetch_pack_args *args, · line 1509
Quoted 10 lines
fetch-pack.c +5
-1@@ -1498,10 +1502,14 @@ static void receive_shallow_info(struct fetch_pack_args *args,* rejected (unless --update-shallow is set); do the same. */ prepare_shallow_info(si, shallows); -if (si->nr_ours || si->nr_theirs) +if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." )); +else +warning (_ ("source repository is shallow." ));OK, so, this is the equivalent of the above for protocol-v2? The same comments apply, then.
Yes, this is for protocol v2.
Quoted 13 lines
Quoted 13 lines
t/t5606-clone-options.sh +0
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=mainexport
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
test_expect_success'setup' '
Quoted 8 lines
Quoted 6 lines
t/t5606-clone-options.sh +0
-0@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
'
+test_expect_success 'fail to clone http shallow repository' 's/fail to clone/reject cloning/, perhaps.
Ok, will do.
Quoted 8 lines
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 77
Quoted 5 lines
t/t5606-clone-options.sh +4
-0+test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repoOK. Also without "--no-reject-shallow" option, the command would successfully clone from the shallow-repo, I presume?
Yes, exactly.
Quoted 3 lines
The changes look more-or-less good to me, except for the "
warning()" bit, which I do not think is a good idea.
I will remove the unnecessary warning() part.
Thanks!
PATCH v8 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Changes since v5:
* camelcase config variable
* warning client that source repo is shallow
* better support ssh:// and git:// protocol v1, v2
Changes since v6:
* use _() for warning/die statement
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v8
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v8
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v7:
1: b957b77bfd79 ! 1: 83a724f6d771 builtin/clone.c: add --reject-shallow option
@@ Commit message
Signed-off-by: lilinchao <[email protected]>
- Reviewed-by: Derrick Stolee <[email protected]>
- Reviewed-by: Junio C Hamano<[email protected]>
- Reviewed-by: Johannes Schindelin <[email protected]>
- Reviewed-by: Jonathan Tan<[email protected]>
-
## Documentation/config/clone.txt ##
@@ Documentation/config/clone.txt: clone.defaultRemoteName::
The name of the remote to create when cloning a repository. Defaults to
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
if (!access(mkpath("%s/shallow", path), F_OK)) {
+ if (reject_shallow)
+ die(_("source repository is shallow, reject to clone."));
-+ else
-+ warning(_("source repository is shallow."));
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
is_local = 0;
@@ fetch-pack.c: static struct ref *do_fetch_pack(struct fetch_pack_args *args,
+ else if (si->nr_ours || si->nr_theirs) {
+ if (args->remote_shallow)
+ die(_("source repository is shallow, reject to clone."));
-+ else
-+ warning(_("source repository is shallow."));
alternate_shallow_file = setup_temporary_shallow(si->shallow);
- else
+ } else
@@ fetch-pack.c: static void receive_shallow_info(struct fetch_pack_args *args,
+ if (si->nr_ours || si->nr_theirs) {
+ if (args->remote_shallow)
+ die(_("source repository is shallow, reject to clone."));
-+ else
-+ warning(_("source repository is shallow."));
alternate_shallow_file =
setup_temporary_shallow(si->shallow);
- else
@@ t/t5606-clone-options.sh: test_expect_success 'disallows --bare with --separate-
'
-+test_expect_success 'fail to clone http shallow repository' '
++test_expect_success 'reject cloning http shallow repository' '
+ git clone --depth=1 --no-local parent shallow-repo &&
+ git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err &&
@@ t/t5606-clone-options.sh: test_expect_success 'disallows --bare with --separate-
+
+'
+
-+test_expect_success 'fail to clone shallow repository' '
++test_expect_success 'reject cloning shallow repository' '
+ rm -rf shallow-repo &&
+ git clone --depth=1 --no-local parent shallow-repo &&
+ test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
@@ t/t5606-clone-options.sh: test_expect_success 'disallows --bare with --separate-
+
+'
+
-+test_expect_success 'fail to clone non-local shallow repository' '
++test_expect_success 'reject cloning non-local shallow repository' '
+ rm -rf shallow-repo &&
+ git clone --depth=1 --no-local parent shallow-repo &&
+ test_must_fail git clone --reject-shallow --no-local shallow-repo out 2>err &&
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
test_cmp expect actual
'
-+test_expect_success 'clone.rejectshallow=true should fail to clone' '
++test_expect_success 'clone.rejectshallow=true should reject cloning' '
+ rm -rf child &&
+ git clone --depth=1 --no-local . child &&
+ test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err &&Documentation/config/clone.txt | 4 +++ Documentation/git-clone.txt | 7 ++++- builtin/clone.c | 22 ++++++++++++++++ fetch-pack.c | 12 ++++++--- fetch-pack.h | 1 + t/t5606-clone-options.sh | 47 ++++++++++++++++++++++++++++++++++ t/t5611-clone-config.sh | 32 +++++++++++++++++++++++ transport.c | 4 +++ transport.h | 4 +++ 9 files changed, 128 insertions(+), 5 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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 + give the default. + --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +22 -0
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,N_ ("force progress reporting" )), +OPT_BOOL (0 ,"reject-shallow" , &option_shallow, +N_ ("don't clone shallow repository" )),OPT_BOOL ('n' ,"no-checkout" , &option_no_checkout,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) + config_shallow =git_config_bool (k, v); +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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;int dest_exists, real_dest_exists =0 ;
@@ -1156,6 +1164,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)*/ git_config (git_clone_config,NULL ); +/* +* If option_shallow is specified from CLI option, +* ignore config_shallow from git_clone_config. +*/ +if (config_shallow !=-1 ) + reject_shallow = config_shallow; + +if (option_shallow !=-1 ) + reject_shallow = option_shallow; +/* * apply the remote name provided by --origin only after this second * call to git_config, to ensure it overrides all config-based values.
@@ -1216,6 +1234,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die (_ ("source repository is shallow, reject to clone." ));if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1227,6 +1247,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);
fetch-pack.c +8 -4
@@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL ); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." )); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &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. */ prepare_shallow_info (si, shallows); -if (si->nr_ours || si->nr_theirs) +if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow) +die (_ ("source repository is shallow, reject to clone." )); alternate_shallow_file =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ; }else { alternate_shallow_file =NULL ;
fetch-pack.h +1 -0
@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned remote_shallow:1; unsigned deepen:1;/*
t/t5606-clone-options.sh +47 -0
59 lines not on this page · raw message
t/t5611-clone-config.sh +32 -0
@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should reject cloning' ' + rm -rf child && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +' + +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' + test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&
transport.c +4 -0
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.remote_shallow = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;
transport.h +4 -0
@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* Reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
base-commit: 84d06cdc06389ae7c462434cb7b1db0980f63860
Signature · 1 line
gitgitgadget
Re: [PATCH v8] builtin/clone.c: add --reject-shallow option
Quoted 3 lines · Li Linchao via GitGitGadget
Changes since v6:
* use
_()for warning/die statement
This round tweaks a few test titles and drops warning() that was given in v7 when the feature is not in use.
Comments from other reviewers who are more familiar with the transport layer than I am? As far as I see, this version is done cleanly enough to call it ready for 'next'.
Thanks.
Re: [PATCH v8] builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetHi,
Quoted 1 line · Li Linchao via GitGitGadget
From: lilinchao <[email protected]>
I see "Li Linchao" in the email, but "lilinchao" in the author information. Maybe you want to align them? Or maybe even use Unicode to write your non-Latinized name?
Quoted 13 lines
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
Quoted 8 lines
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
Good.
I like most of the patch, and will only point out a couple of things that I think can be improved even further.
Documentation/git-clone.txt objects from the source repository into a pack in the cloned repository. · line 155
Quoted 12 lines
Documentation/git-clone.txt +4
-0@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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 + give the default.
I am not a native speaker, either, but I believe that it would "roll off the tongue" a bit better to say "to specify the default".
Quoted 9 lines
Documentation/git-clone.txt +1
-0+ --bare:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrativebuiltin/clone.c +0
-0
builtin/clone.c static int option_no_checkout, option_bare, option_mirror, option_single_branch · line 54
Quoted 5 lines
builtin/clone.c +2
-0@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */
I would much prefer those variable names to include an indicator that this is about _rejecting_ shallow clones. I.e. option_reject_shallow.
Also, I think that we can do with just a single option_reject_shallow (we do not even need that reject_shallow variable in cmd_clone()):
- in git_clone_config(), only override it if it is still unspecified:
if (!strcmp(k, "clone.rejectshallow") && option_reject_shallow < 0) option_reject_shallow = git_config_bool(k,v);
- in cmd_clone(), test for a _positive_ value:
if (option_reject_shallow > 0)
die(_("source repository is shallow, reject to clone."));and
if (option_reject_shallow > 0)
transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
One thing to note (in the commit message, would be my preference) is that cmd_clone() is _particular_ in that it runs git_config() _twice_. Once before the command-line options are parsed, and once after the new Git repository has been initialized. Note that my suggestion still works with
that: if either the original config, or the new config set clone.rejectShallow, it is picked up correctly, with the latter overriding the former if both configs want to set it.
fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1133
Quoted 11 lines
fetch-pack.c +2
-1@@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,NULL ); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow)
Even as a non-casual reader, this name remote_shallow leads me to assume incorrect things. This option is not about wanting a remote shallow repository, it is about rejecting a remote shallow repository.
Please name this attribute reject_shallow instead of remote_shallow. That will prevent future puzzlement.
Quoted 13 lines
fetch-pack.c +2
-1+die (_ ("source repository is shallow, reject to clone." )); alternate_shallow_file =setup_temporary_shallow (si->shallow); - else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &gitmodules_oids))t/t5606-clone-options.sh +0
-0
t/t5606-clone-options.sh GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main · line 9
Quoted 5 lines
t/t5606-clone-options.sh +2
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpd
That's not good. What happens if there is no httpd? Then the rest of the tests are either skipped, or if GIT_TEST_HTTPD is set to true, we fail. The failure is intentional, but the skipping is not. There are many tests in t5606 that do not require a running HTTP daemon, and we should not skip them (for example, in our CI runs, there are quite a few jobs that run without any working httpd).
A much better alternative, I think, would be to move those new test cases that require httpd to be running to t5601 (which _already_ calls start_httpd, near the end, so as to not skip any tests that do not require httpd).
Quoted 7 lines
t/t5606-clone-options.sh +0
-0test_expect_success 'setup' '@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' ' '
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 59
Quoted 10 lines
t/t5606-clone-options.sh +10
-0+test_expect_success 'reject cloning http shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'reject cloning shallow repository' ' + rm -rf shallow-repo &&
Should this line not come immediately after the bare clone into <DOCUMENT_ROOT>/repo.git? Or even better, as a test_when_finished command.
And maybe you want to extract this preparatory step into its own test case:
test_expect_success 'set up shallow http repository' '
test_when_finished "rm -rf shallow-repo" && git clone --depth=1 --no-local parent shallow-repo && git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"
'
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 63
Quoted 4 lines
t/t5606-clone-options.sh +4
-0+ git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +
Please remove the extra empty line. (This goes for at least a couple test cases added by this patch.)
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 64
Quoted 1 line
t/t5606-clone-options.sh +1
-0+'
This test case does not require start_httpd, and should therefore come before the test cases that do require it (actually, it should come before the start_httpd call, even).
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 72
Quoted 8 lines
t/t5606-clone-options.sh +8
-0+ +test_expect_success 'reject cloning non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +'
Hmm. Reading through three test cases that all create shallow-repo in the same way, I wonder whether we should not simply set it up once, and then not even bother removing it. I think that would simplify not only the patch, it would also simplify debugging later on.
Quoted 12 lines
t/t5606-clone-options.sh +12
-0+ +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repo
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 94
Quoted 10 lines
t/t5606-clone-options.sh +10
-0+ +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' +
Having read through these test cases, I think they can be simplified by
- first setting up shallow-repo
- then testing in the same test case whether --reject-shallow fails and --no-reject-shallow succeeds, without --no-local
- then testing the same _with_ --no-local
These can go to t5606, no problem.
Then, in t5601, after the start_httpd call, add a single test case that
- sets up the shallow clone _directly_, i.e.
git clone --bare --no-local --depth=1 parent \ "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"
- verifies that --reject-shallow fails as expected, and
- verifies that --no-reject-shallow works as expected.
Quoted 8 lines
t/t5606-clone-options.sh +0
-0test_expect_success 'uses "origin" for default remote name' ' git clone parent clone-default-origin &&t/t5611-clone-config.sh +0
-0
t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 100
Quoted 6 lines
t/t5611-clone-config.sh +3
-0@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' test_cmp expect actual ' +test_expect_success 'clone.rejectshallow=true should reject cloning' ' + rm -rf child && + git clone --depth=1 --no-local . child &&
In the following, this shallow repository is needed a couple of times. Better set it up once, in a dedicated set up shallow repository test case.
And shallow-repo would probably make for a much better name than child.
t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 109
Quoted 9 lines
t/t5611-clone-config.sh +9
-0+ test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +'
These two can be combined (and should, if you ask me, to simplify things).
Quoted 10 lines
t/t5611-clone-config.sh +10
-0+ +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child &&
t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 129
Quoted 10 lines
t/t5611-clone-config.sh +10
-0+ test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' +
Personally, I think this is overkill. What I would do is to have a single test case that verifies that
- clone.rejectShallow=true fails as expected,
- clone.rejectShallow=false [...] --reject-shallow fails as expected, and
- clone.rejectShallow=false succeeds.
If we do this, we do not even need a preparatory test case setting up the shallow repository.
transport.c static int set_git_option(struct git_transport_options *opts, · line 240
Quoted 13 lines
t/t5611-clone-config.sh +0
-0test_expect_success MINGW 'clone -c core.hideDotFiles' ' test_commit attributes .gitattributes "" && rm -rf child &&transport.c +2
-0@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value;
I see that this is the established pattern (I am so grateful that I have
https://github.com/gitgitgadget/git/pull/865/files to look at the context, something with which a pure mail-only patch contribution would not bless me!), that those Boolean options are NULL vs non-NULL. So while you pass "1" as the value parameter to set_git_option(), the parameter "0" would _enable that option just the same_, you would have to pass NULL to turn it off. I find that highly unintuitive, but that's not the fault of your patch. The pattern is established, and you did the right thing by following it.
transport.c static int set_git_option(struct git_transport_options *opts, · line 244
Quoted 4 lines
transport.c +1
-0+return 0 ; }return 1 ; }
As I said, the rest of the patch looks good to me. With the few suggestions I offered, I would be totally fine with this patch entering next.
Thank you,
Dscho
Re: [PATCH v8] builtin/clone.c: add --reject-shallow option
Quoted 5 lines · Johannes Schindelin
builtin/clone.c static int option_no_checkout, option_bare, option_mirror, option_single_branch · line 54
Quoted 2 lines
builtin/clone.c +2
-0+static int option_shallow =-1 ;/* unspecified */ +static int config_shallow =-1 ;/* unspecified */ I would much prefer those variable names to include an indicator that this is about _rejecting_ shallow clones. I.e.
option_reject_shallow.
Good.
Quoted 4 lines
... repository has been initialized. Note that my suggestion still works with
that: if either the original config, or the new config setclone.rejectShallow, it is picked up correctly, with the latter overriding the former if both configs want to set it.
All four combinations ("set it to true" vs "set it to false" makes two, and before and after doubles that to four)?
Quoted 7 lines
Quoted 7 lines
fetch-pack.c +0
-0@@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen) setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
Quoted 8 lines
fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1133
Quoted 4 lines
fetch-pack.c +2
-1NULL); - else if (si->nr_ours || si->nr_theirs) + else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow)Even as a non-casual reader, this name
remote_shallowleads me to assume incorrect things. This option is not about wanting a remote shallow repository, it is about rejecting a remote shallow repository.
Yeah, I've seen this code too long that my eyes were contaminated ;-) Thanks for an extra set of eyeballs to spot this. What this option means is to "reject-shallow-remote", and I agree 'reject' is the most important part (args->reject_shallow_remote is not overly long, either).
Quoted 18 lines
t/t5606-clone-options.sh GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main · line 9
Quoted 10 lines
t/t5606-clone-options.sh +2
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpdThat's not good. What happens if there is no
httpd? Then the rest of the tests are either skipped, or ifGIT_TEST_HTTPDis set totrue, we fail. The failure is intentional, but the skipping is not. There are many tests in t5606 that do not require a running HTTP daemon, and we should not skip them (for example, in our CI runs, there are quite a few jobs that run without any workinghttpd).
Quoted 4 lines
A much better alternative, I think, would be to move those new test cases that require
httpdto be running to t5601 (which _already_ callsstart_httpd, near the end, so as to not skip any tests that do not requirehttpd).
Or move the tests that require httpd, and use of httpd library, to the end of this script.
Quoted 13 lines
Having read through these test cases, I think they can be simplified by
- first setting up
shallow-repo- then testing in the same test case whether
--reject-shallowfails and--no-reject-shallowsucceeds, without--no-local- then testing the same _with_
--no-localThese can go to t5606, no problem.
Then, in t5601, after the
start_httpdcall, add a single test case that
Quoted 10 lines
- sets up the shallow clone _directly_, i.e.
git clone --bare --no-local --depth=1 parent \ "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"- verifies that
--reject-shallowfails as expected, and- verifies that
--no-reject-shallowworks as expected.Quoted 1 line
t/t5606-clone-options.sh +0
-0test_expect_success 'uses "origin" for default remote name' '
That would work.
Quoted 4 lines
...
As I said, the rest of the patch looks good to me. With the few suggestions I offered, I would be totally fine with this patch enteringnext.
Thanks for a review. Looking good.
Re: Re: [PATCH v8] builtin/clone.c: add --reject-shallow option
In reply to a message not in the archiveThanks for your suggestions!
I've combined your suggestions in this comment with Junio's which based on yours.
Quoted 10 lines
Hi,
Quoted 1 line · Li Linchao via GitGitGadget
From: lilinchao <[email protected]>
I see "Li Linchao" in the email, but "lilinchao" in the author information. Maybe you want to align them? Or maybe even use Unicode to write your non-Latinized name?
The "Li Lilinchao" comes from my Github profile name. Actually, it contains my first name and last name respectively.
I will changed it to "Li Linchao" in the author info to keep these info consistent.
Quoted 343 lines
Quoted 13 lines
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
Quoted 8 lines
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
Good.
I like most of the patch, and will only point out a couple of things that I think can be improved even further.
Documentation/git-clone.txt objects from the source repository into a pack in the cloned repository. · line 155
Quoted 12 lines
Documentation/git-clone.txt +0
-0@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository.--no-checkout::
No checkout of HEAD is performed after the clone is complete.+--[no-]reject-shallow::
Documentation/git-clone.txt +3
-0+ Fail if the source repository is a shallow repository. + The 'clone.rejectShallow' configuration variable can be used to + give the default.I am not a native speaker, either, but I believe that it would "roll off the tongue" a bit better to say "to specify the default".
Quoted 9 lines
+
--bare::
Make a 'bare' Git repository. That is, instead of creating<directory>and placing the administrativebuiltin/clone.c +0
-0builtin/clone.c static int option_no_checkout, option_bare, option_mirror, option_single_branch · line 54
Quoted 5 lines
builtin/clone.c +2
-0@@ -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_no_tags; static int option_shallow_submodules; +static int option_shallow = -1; /* unspecified */ +static int config_shallow = -1; /* unspecified */I would much prefer those variable names to include an indicator that this is about _rejecting_ shallow clones. I.e.
option_reject_shallow.Also, I think that we can do with just a single
option_reject_shallow(we do not even need thatreject_shallowvariable incmd_clone()):- in
git_clone_config(), only override it if it is still unspecified:if (!strcmp(k, "clone.rejectshallow") && option_reject_shallow < 0) option_reject_shallow = git_config_bool(k,v);- in
cmd_clone(), test for a _positive_ value:if (option_reject_shallow > 0) die(_("source repository is shallow, reject to clone."));and
if (
option_reject_shallow> 0)transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");One thing to note (in the commit message, would be my preference) is that
cmd_clone()is _particular_ in that it runsgit_config()_twice_. Once before the command-line options are parsed, and once after the new Git repository has been initialized. Note that my suggestion still works with
that: if either the original config, or the new config setclone.rejectShallow, it is picked up correctly, with the latter overriding the former if both configs want to set it.fetch-pack.c static struct ref *do_fetch_pack(struct fetch_pack_args *args, · line 1133
Quoted 11 lines
fetch-pack.c +2
-1@@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, if (args->deepen) setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); -else if (si->nr_ours || si->nr_theirs) +else if (si->nr_ours || si->nr_theirs) { +if (args->remote_shallow)Even as a non-casual reader, this name
remote_shallowleads me to assume incorrect things. This option is not about wanting a remote shallow repository, it is about rejecting a remote shallow repository.Please name this attribute
reject_shallowinstead ofremote_shallow. That will prevent future puzzlement.Quoted 15 lines
fetch-pack.c +2
-1+die (_ ("source repository is shallow, reject to clone." )); alternate_shallow_file = setup_temporary_shallow(si->shallow); - else + }else alternate_shallow_file = NULL; if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought, &gitmodules_oids))t/t5606-clone-options.sh +0
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=mainexport
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAMEQuoted 3 lines
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpdThat's not good. What happens if there is no
httpd? Then the rest of the tests are either skipped, or ifGIT_TEST_HTTPDis set totrue, we fail. The failure is intentional, but the skipping is not. There are many tests in t5606 that do not require a running HTTP daemon, and we should not skip them (for example, in our CI runs, there are quite a few jobs that run without any workinghttpd).A much better alternative, I think, would be to move those new test cases that require
httpdto be running to t5601 (which _already_ callsstart_httpd, near the end, so as to not skip any tests that do not requirehttpd).Quoted 7 lines
test_expect_success'setup' 't/t5606-clone-options.sh +0
-0@@ -45,6 +47,51 @@ test_expect_success 'disallows --bare with --separate-git-dir' ''
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 59
Quoted 10 lines
t/t5606-clone-options.sh +10
-0+test_expect_success 'reject cloning http shallow repository' ' + git clone --depth=1 --no-local parent shallow-repo && + git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err + +' + +test_expect_success 'reject cloning shallow repository' ' + rm -rf shallow-repo &&Should this line not come immediately after the bare clone into <DOCUMENT_ROOT>/repo.git? Or even better, as a
test_when_finishedcommand.And maybe you want to extract this preparatory step into its own test case:
test_expect_success'set up shallow http repository' 'test_when_finished "rm -rf shallow-repo" && git clone --depth=1 --no-local parent shallow-repo && git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"'
t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 63
Quoted 4 lines
t/t5606-clone-options.sh +4
-0+ git clone --depth=1 --no-local parent shallow-repo && + test_must_fail git clone --reject-shallow shallow-repo out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +Please remove the extra empty line. (This goes for at least a couple test cases added by this patch.)
Quoted 1 line
+'
This test case does not require
start_httpd, and should therefore come before the test cases that do require it (actually, it should come before thestart_httpdcall, even).t/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 72
Quoted 8 lines
t/t5606-clone-options.sh +8
-0+ +test_expect_success 'reject cloning non-local shallow repository' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-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 + +'Hmm. Reading through three test cases that all create
shallow-repoin the same way, I wonder whether we should not simply set it up once, and then not even bother removing it. I think that would simplify not only the patch, it would also simplify debugging later on.Quoted 12 lines
t/t5606-clone-options.sh +12
-0+ +test_expect_success 'clone shallow repository with --no-reject-shallow' ' + rm -rf shallow-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone --no-reject-shallow --no-local shallow-repo clone-repo + +' + +test_expect_success 'clone normal repository with --reject-shallow' ' + rm -rf clone-repo && + git clone --no-local parent normal-repo && + git clone --reject-shallow --no-local normal-repo clone-repot/t5606-clone-options.sh test_expect_success 'disallows --bare with --separate-git-dir' ' · line 94
Quoted 10 lines
t/t5606-clone-options.sh +10
-0+ +' + +test_expect_success 'unspecified any configs or options' ' + rm -rf shallow-repo clone-repo && + git clone --depth=1 --no-local parent shallow-repo && + git clone shallow-repo clone-repo + +' +Having read through these test cases, I think they can be simplified by
- first setting up
shallow-repo- then testing in the same test case whether
--reject-shallowfails and--no-reject-shallowsucceeds, without--no-local- then testing the same _with_
--no-localThese can go to t5606, no problem.
Then, in t5601, after the
start_httpdcall, add a single test case that- sets up the shallow clone _directly_, i.e.
git clone --bare --no-local --depth=1 parent \ "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"- verifies that
--reject-shallowfails as expected, and- verifies that
--no-reject-shallowworks as expected.Quoted 11 lines
test_expect_success'uses "origin" for default remote name' 'git clone parent clone-default-origin &&
t/t5611-clone-config.sh +0
-0@@ -95,6 +95,38 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' '
test_cmpexpect actual
't/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 100
Quoted 3 lines
t/t5611-clone-config.sh +3
-0+test_expect_success 'clone.rejectshallow=true should reject cloning' ' + rm -rf child && + git clone --depth=1 --no-local . child &&In the following, this shallow repository is needed a couple of times. Better set it up once, in a dedicated
set up shallow repositorytest case.And
shallow-repowould probably make for a much better name thanchild.t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 109
Quoted 9 lines
t/t5611-clone-config.sh +9
-0+ test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'clone.rejectshallow=false should succeed' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=false clone --no-local child out +'These two can be combined (and should, if you ask me, to simplify things).
Quoted 10 lines
t/t5611-clone-config.sh +10
-0+ +test_expect_success 'clone.rejectshallow=true should succeed with normal repo' ' + rm -rf child out && + git clone --no-local . child && + git -c clone.rejectshallow=true clone --no-local child out +' + +test_expect_success 'option --reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child &&t/t5611-clone-config.sh test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' · line 129
Quoted 10 lines
t/t5611-clone-config.sh +10
-0+ test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err && + test_i18ngrep -e "source repository is shallow, reject to clone." err +' + +test_expect_success 'option --no-reject-shallow override clone.rejectshallow' ' + rm -rf child out && + git clone --depth=1 --no-local . child && + git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child out +' +Personally, I think this is overkill. What I would do is to have a single test case that verifies that
-
clone.rejectShallow=truefails as expected,-
clone.rejectShallow=false [...] --reject-shallowfails as expected, and-
clone.rejectShallow=falsesucceeds.If we do this, we do not even need a preparatory test case setting up the shallow repository.
transport.c static int set_git_option(struct git_transport_options *opts, · line 240
Quoted 13 lines
test_expect_successMINGW 'clone -c core.hideDotFiles' 'test_commitattributes .gitattributes "" &&
rm -rf child &&transport.c +2
-0@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts, list_objects_filter_die_if_populated(&opts->filter_options); parse_list_objects_filter(&opts->filter_options, value); return 0; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value;I see that this is the established pattern (I am so grateful that I have
https://github.com/gitgitgadget/git/pull/865/files to look at the context, something with which a pure mail-only patch contribution would not bless me!), that those Boolean options areNULLvs non-NULL. So while you pass"1"as thevalueparameter toset_git_option(), the parameter"0"would_enablethat option just thesame_, you would have to passNULLto turn it off. I find that highly unintuitive, but that's not the fault of your patch. The pattern is established, and you did the right thing by following it.transport.c static int set_git_option(struct git_transport_options *opts, · line 244
Quoted 4 lines
transport.c +1
-0+return 0 ; } return 1; }As I said, the rest of the patch looks good to me. With the few suggestions I offered, I would be totally fine with this patch entering
next.Thank you,
Dscho
Re: [PATCH v8] builtin/clone.c: add --reject-shallow option
In reply to Junio C HamanoHi Junio,
Quoted 9 lines · Junio C Hamano
Quoted 4 lines · Johannes Schindelin
... repository has been initialized. Note that my suggestion still works with
that: if either the original config, or the new config setclone.rejectShallow, it is picked up correctly, with the latter overriding the former if both configs want to set it.All four combinations ("set it to true" vs "set it to false" makes two, and before and after doubles that to four)?
I don't think we need to test all four combinations, that's part of my point. We only need to verify that we can reject a shallow clone, and that we can allow it, and that the command-line option overrides the config option. That's three ;-)
Quoted 18 lines
Quoted 18 lines
t/t5606-clone-options.sh GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main · line 9
Quoted 10 lines
t/t5606-clone-options.sh +2
-0@@ -5,6 +5,8 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpdThat's not good. What happens if there is no
httpd? Then the rest of the tests are either skipped, or ifGIT_TEST_HTTPDis set totrue, we fail. The failure is intentional, but the skipping is not. There are many tests in t5606 that do not require a running HTTP daemon, and we should not skip them (for example, in our CI runs, there are quite a few jobs that run without any workinghttpd).
Quoted 7 lines
Quoted 4 lines
A much better alternative, I think, would be to move those new test cases that require
httpdto be running to t5601 (which _already_ callsstart_httpd, near the end, so as to not skip any tests that do not requirehttpd).Or move the tests that require httpd, and use of httpd library, to the end of this script.
In the interest of saving some time during the already-quite-long test runs, I would recommend piggy-backing onto a script that _already_ spins up its own Apache server.
Thanks,
Dscho
PATCH v9 1/1 builtin/clone.c: add --reject-shallow option
In reply to Li Linchao via GitGitGadgetFrom: lilinchao <[email protected]>
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, users should have the option to refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity, so we can't pass 'x' value to --depth, and expect this can obtain a complete history of a repository.
In other scenarios, if we have an API that allow us to import external repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Changes since v5:
* camelcase config variable
* warning client that source repo is shallow
* better support ssh:// and git:// protocol v1, v2
Changes since v6:
* use _() for warning/die statement
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v9
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v9
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v8:
1: 83a724f6d771 ! 1: 11043a2344dd builtin/clone.c: add --reject-shallow option
@@ Commit message
This patch offers a new option '--reject-shallow' that can reject to
clone a shallow repository.
- Signed-off-by: lilinchao <[email protected]>
+ Signed-off-by: Li Linchao <[email protected]>
## Documentation/config/clone.txt ##
@@ Documentation/config/clone.txt: clone.defaultRemoteName::
@@ Documentation/git-clone.txt: objects from the source repository into a pack in t
+--[no-]reject-shallow::
+ Fail if the source repository is a shallow repository.
+ The 'clone.rejectShallow' configuration variable can be used to
-+ give the default.
++ specify the default.
+
--bare::
Make a 'bare' Git repository. That is, instead of
@@ builtin/clone.c: static int option_no_checkout, option_bare, option_mirror, opti
static int option_local = -1, option_no_hardlinks, option_shared;
static int option_no_tags;
static int option_shallow_submodules;
-+static int option_shallow = -1; /* unspecified */
-+static int config_shallow = -1; /* unspecified */
++static int option_reject_shallow = -1; /* unspecified */
static int deepen;
static char *option_template, *option_depth, *option_since;
static char *option_origin = NULL;
@@ builtin/clone.c: static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
N_("force progress reporting")),
-+ OPT_BOOL(0, "reject-shallow", &option_shallow,
++ OPT_BOOL(0, "reject-shallow", &option_reject_shallow,
+ N_("don't clone shallow repository")),
OPT_BOOL('n', "no-checkout", &option_no_checkout,
N_("don't create a checkout")),
@@ builtin/clone.c: static int git_clone_config(const char *k, const char *v, void
free(remote_name);
remote_name = xstrdup(v);
}
-+ if (!strcmp(k, "clone.rejectshallow"))
-+ config_shallow = git_config_bool(k, v);
++ if (!strcmp(k, "clone.rejectshallow") && option_reject_shallow < 0)
++ option_reject_shallow = git_config_bool(k, v);
+
return git_default_config(k, v, cb);
}
-@@ builtin/clone.c: static int path_exists(const char *path)
- int cmd_clone(int argc, const char **argv, const char *prefix)
- {
- int is_bundle = 0, is_local;
-+ int reject_shallow = 0;
- const char *repo_name, *repo, *work_tree, *git_dir;
- char *path, *dir, *display_repo = NULL;
- int dest_exists, real_dest_exists = 0;
-@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
- */
- git_config(git_clone_config, NULL);
-
-+ /*
-+ * If option_shallow is specified from CLI option,
-+ * ignore config_shallow from git_clone_config.
-+ */
-+ if (config_shallow != -1)
-+ reject_shallow = config_shallow;
-+
-+ if (option_shallow != -1)
-+ reject_shallow = option_shallow;
-+
- /*
- * apply the remote name provided by --origin only after this second
- * call to git_config, to ensure it overrides all config-based values.
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
if (filter_options.choice)
warning(_("--filter is ignored in local clones; use file:// instead."));
if (!access(mkpath("%s/shallow", path), F_OK)) {
-+ if (reject_shallow)
++ if (option_reject_shallow > 0)
+ die(_("source repository is shallow, reject to clone."));
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
-+ if (reject_shallow)
++ if (option_reject_shallow > 0)
+ transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
if (option_depth)
transport_set_option(transport, TRANS_OPT_DEPTH,
@@ fetch-pack.c: static struct ref *do_fetch_pack(struct fetch_pack_args *args,
NULL);
- else if (si->nr_ours || si->nr_theirs)
+ else if (si->nr_ours || si->nr_theirs) {
-+ if (args->remote_shallow)
++ if (args->reject_shallow_remote)
+ die(_("source repository is shallow, reject to clone."));
alternate_shallow_file = setup_temporary_shallow(si->shallow);
- else
@@ fetch-pack.c: static void receive_shallow_info(struct fetch_pack_args *args,
prepare_shallow_info(si, shallows);
- if (si->nr_ours || si->nr_theirs)
+ if (si->nr_ours || si->nr_theirs) {
-+ if (args->remote_shallow)
++ if (args->reject_shallow_remote)
+ die(_("source repository is shallow, reject to clone."));
alternate_shallow_file =
setup_temporary_shallow(si->shallow);
@@ fetch-pack.h: struct fetch_pack_args {
unsigned self_contained_and_connected:1;
unsigned cloning:1;
unsigned update_shallow:1;
-+ unsigned remote_shallow:1;
++ unsigned reject_shallow_remote:1;
unsigned deepen:1;
/*
- ## t/t5606-clone-options.sh ##
-@@ t/t5606-clone-options.sh: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
- export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+ ## t/t5601-clone.sh ##
+@@ t/t5601-clone.sh: test_expect_success 'partial clone using HTTP' '
+ partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
+ '
- . ./test-lib.sh
-+. "$TEST_DIRECTORY"/lib-httpd.sh
-+start_httpd
++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
+ # test script is only executed when httpd is available and enabled.
+
+
+ ## t/t5606-clone-options.sh ##
+@@ t/t5606-clone-options.sh: test_expect_success 'setup' '
+ mkdir parent &&
+ (cd parent && git init &&
+ echo one >file && git add file &&
+- git commit -m one)
++ git commit -m one) &&
++ git clone --depth=1 --no-local parent shallow-repo
- test_expect_success 'setup' '
+ '
@@ t/t5606-clone-options.sh: test_expect_success 'disallows --bare with --separate-git-dir' '
'
-+test_expect_success 'reject cloning http shallow repository' '
-+ git clone --depth=1 --no-local parent shallow-repo &&
-+ git clone --bare --no-local shallow-repo "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
-+ test_must_fail git clone --reject-shallow $HTTPD_URL/smart/repo.git out 2>err &&
-+ test_i18ngrep -e "source repository is shallow, reject to clone." err
-+
-+'
-+
+test_expect_success 'reject cloning shallow repository' '
-+ rm -rf shallow-repo &&
-+ git clone --depth=1 --no-local parent shallow-repo &&
++ 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
++ 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' '
-+ rm -rf shallow-repo &&
-+ git clone --depth=1 --no-local parent shallow-repo &&
++ 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
++ test_i18ngrep -e "source repository is shallow, reject to clone." err &&
+
++ git clone --no-reject-shallow --no-local shallow-repo repo
+'
+
-+test_expect_success 'clone shallow repository with --no-reject-shallow' '
-+ rm -rf shallow-repo &&
-+ git clone --depth=1 --no-local parent shallow-repo &&
-+ git clone --no-reject-shallow --no-local shallow-repo clone-repo
-+
-+'
-+
-+test_expect_success 'clone normal repository with --reject-shallow' '
-+ rm -rf clone-repo &&
-+ git clone --no-local parent normal-repo &&
-+ git clone --reject-shallow --no-local normal-repo clone-repo
-+
-+'
-+
-+test_expect_success 'unspecified any configs or options' '
-+ rm -rf shallow-repo clone-repo &&
-+ git clone --depth=1 --no-local parent shallow-repo &&
-+ git clone shallow-repo clone-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' '
@@ t/t5611-clone-config.sh: test_expect_success 'clone -c remote.<remote>.fetch=<re
test_cmp expect actual
'
-+test_expect_success 'clone.rejectshallow=true should reject cloning' '
-+ rm -rf child &&
-+ git clone --depth=1 --no-local . child &&
-+ test_must_fail git -c clone.rejectshallow=true clone --no-local child out 2>err &&
-+ test_i18ngrep -e "source repository is shallow, reject to clone." err
++test_expect_success 'set up shallow repository' '
++ git clone --depth=1 --no-local . shallow-repo
+'
+
-+test_expect_success 'clone.rejectshallow=false should succeed' '
-+ rm -rf child out &&
-+ git clone --depth=1 --no-local . child &&
-+ git -c clone.rejectshallow=false clone --no-local child out
-+'
++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 &&
+
-+test_expect_success 'clone.rejectshallow=true should succeed with normal repo' '
-+ rm -rf child out &&
-+ git clone --no-local . child &&
-+ git -c clone.rejectshallow=true clone --no-local child out
++ git -c clone.rejectshallow=false clone --no-local shallow-repo out
+'
+
-+test_expect_success 'option --reject-shallow override clone.rejectshallow' '
-+ rm -rf child out &&
-+ git clone --depth=1 --no-local . child &&
-+ test_must_fail git -c clone.rejectshallow=false clone --reject-shallow --no-local child out 2>err &&
-+ test_i18ngrep -e "source repository is shallow, reject to clone." err
++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 'option --no-reject-shallow override clone.rejectshallow' '
-+ rm -rf child out &&
-+ git clone --depth=1 --no-local . child &&
-+ git -c clone.rejectshallow=true clone --no-reject-shallow --no-local child 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' '
@@ transport.c: static int fetch_refs_via_pack(struct transport *transport,
args.stateless_rpc = transport->stateless_rpc;
args.server_options = transport->server_options;
args.negotiation_tips = data->options.negotiation_tips;
-+ args.remote_shallow = transport->smart_options->reject_shallow;
++ args.reject_shallow_remote = transport->smart_options->reject_shallow;
if (!data->got_remote_heads) {
int i;Documentation/config/clone.txt | 4 ++++ Documentation/git-clone.txt | 7 ++++++- builtin/clone.c | 10 ++++++++++ fetch-pack.c | 12 ++++++++---- fetch-pack.h | 1 + t/t5601-clone.sh | 9 +++++++++ t/t5606-clone-options.sh | 27 ++++++++++++++++++++++++++- t/t5611-clone-config.sh | 25 +++++++++++++++++++++++++ transport.c | 4 ++++ transport.h | 4 ++++ 10 files changed, 97 insertions(+), 6 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +10 -0
@@ -50,6 +50,7 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_reject_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +91,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,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,N_ ("don't create a checkout" )), OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
@@ -858,6 +861,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" ) && option_reject_shallow <0 ) + option_reject_shallow =git_config_bool (k, v); +return git_default_config (k, v, cb); }
@@ -1216,6 +1222,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (filter_options.choice)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (option_reject_shallow >0 ) +die (_ ("source repository is shallow, reject to clone." ));if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); is_local =0 ;
@@ -1227,6 +1235,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)transport_set_option (transport,TRANS_OPT_KEEP ,"yes" ); +if (option_reject_shallow >0 ) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);
fetch-pack.c +8 -4
@@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,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); -else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &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. */ 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 =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ; }else { alternate_shallow_file =NULL ;
fetch-pack.h +1 -0
@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned reject_shallow_remote:1; unsigned deepen:1;/*
t/t5601-clone.sh +9 -0
@@ -759,6 +759,15 @@ test_expect_success 'partial clone using HTTP' ' 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 # test script is only executed when httpd is available and enabled.
t/t5606-clone-options.sh +26 -1
@@ -11,7 +11,8 @@ test_expect_success 'setup' ' mkdir parent && (cd parent && git init && 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' ' git clone parent clone-default-origin &&
t/t5611-clone-config.sh +25 -0
@@ -95,6 +95,31 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' 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_commit attributes .gitattributes "" && rm -rf child &&
transport.c +4 -0
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.reject_shallow_remote = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;
transport.h +4 -0
@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* Reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
base-commit: a65ce7f831aa5fcc596c6d23fcde543d98b39bd7
Signature · 1 line
gitgitgadget
Re: [PATCH v9] builtin/clone.c: add --reject-shallow option
Quoted 1 line · lilinchao via GitGitGadget
From: lilinchao <[email protected]>
This is not corrected, and no longer matches your sign-off.
I can edit your 'From:' to match this time, but please make sure they match for the next time.
Quoted 4 lines
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, users should have the option to
I find the "should" too strong, but let's keep reading.
Quoted 2 lines
refuse to clone this kind of repository, and may want to exit the process immediately without creating any unnecessary files.
Yes, that is too strong and also redundant.
Quoted 2 lines
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, but as the unshallow cloning's depth
"Although"; if you begin with "although", you shouldn't write "but".
Quoted 4 lines
is INFINITY, we can't know exactly the minimun 'x' value that can satisfy the minimum integrity,
so we can't pass 'x' value to --depth,
and expect this can obtain a complete history of a repository.
If the argument were "we might start with depth x, and the source may be deep enough to give us x right now, but we may want to deepen more than they can offer, and such a user would want to be able to say 'I want depth=x now, but make sure they are not shallow'", I would understand it, but I do not see where the "minimum integrity" comes from---there doesn't appear to be anything related to integrity here.
Quoted 1 line
In other scenarios, if we have an API that allow us to import external
"allows"
Quoted 4 lines
repository, and then perform various operations on the repo. But if the imported is a shallow one(which is actually possible), it will affect the subsequent operations. So we can choose to refuse to clone, and let's just import a normal repository.
I'd suggest dropping this entire paragraph. That is not any new scenario at all. API or not, you essentially just said "you can do various things on your clone once you have it, but some things you may want to do you would want a full history". That is what you started the whole discussion above and does not add any new information.
Quoted 2 lines
This patch offers a new option '--reject-shallow' that can reject to clone a shallow repository.
Teach '--reject-shallow' option to "git clone" to abort as soon as we find out that we are cloning from a shallow repository.
perhaps? cf. Documentation/SubmittingPatches[[describe-changes]] especially [[imperative-mood]].
Quoted 9 lines
Signed-off-by Li Linchao <[email protected]>---
builtin/clone.c: add --reject-shallow optionChanges since v1:
...
Changes since v6:* use
_()for warning/die statement
What are the more recent changes?
builtin/clone.c static int git_clone_config(const char *k, const char *v, void *cb) · line 865
Quoted 8 lines
Signed-off-by lilinchao [email protected]builtin/clone.c +2
-0@@ -858,6 +861,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" ) && option_reject_shallow <0 ) + option_reject_shallow =git_config_bool (k, v);
Does this "single variable is enough" really work?
Imagine that the first time around we'd read from $HOME/.gitconfig that says true (flips the variable from "unspecified"). Further imagine that we are running "git clone -c config.rejectShallow=no" to countermand the global config. We call write_config() to write the extra configuration value out, and then call git_config() to read from the repository configuration again.
Because of the value taken from $HOME/.gitconfig, however, the attempt to override is silently ignored, isn't it?
Other than that, the changes to the code from the previous round looked sensible.
Re: [PATCH v9] builtin/clone.c: add --reject-shallow option
Hi Junio,
Quoted 16 lines · Junio C Hamano
builtin/clone.c static int git_clone_config(const char *k, const char *v, void *cb) · line 865
Quoted 6 lines
builtin/clone.c +2
-0@@ -858,6 +861,9 @@ static int git_clone_config(const char *k, const char *v, void *cb)free (remote_name); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" ) && option_reject_shallow <0 ) + option_reject_shallow =git_config_bool (k, v);Does this "single variable is enough" really work?
Imagine that the first time around we'd read from $HOME/.gitconfig that says true (flips the variable from "unspecified"). Further imagine that we are running "git clone -c config.rejectShallow=no" to countermand the global config. We call
write_config()to write the extra configuration value out, and then callgit_config()to read from the repository configuration again.
Quoted 2 lines
Because of the value taken from $HOME/.gitconfig, however, the attempt to override is silently ignored, isn't it?
That's my mistake, and you don't even need a second config to see the problem:
[clone]
rejectShallow = false
rejectShallow = true
Clearly, the second one should override the first one, but the code I suggested (and which was integrated into this iteration) simply does not work correctly.
So yes, I think you're right, and we need to have that second variable, and then do something like this:
if (option_reject_shallow < 0) option_reject_shallow = config_reject_shallow;
Sorry for the trouble!
Dscho
Re: [PATCH v9] builtin/clone.c: add --reject-shallow option
Quoted 8 lines · Johannes Schindelin
Quoted 2 lines
Does this "single variable is enough" really work?
...That's my mistake, and you don't even need a second config to see the problem:
[clone]
rejectShallow = false
rejectShallow = true
Yup, that is a much simpler example.
Quoted 1 line
Sorry for the trouble!
Don't feel bad---in an earlier round of review I made a similar mistake to wonder if these two variables can be reduced into one myself ;-). As you said, this one is special in making two calls to git_config() and need to be handled carefully.
Thanks.
PATCH v10 1/1 builtin/clone.c: add --reject-shallow option
In reply to lilinchao via GitGitGadgetFrom: Li Linchao <[email protected]>
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.
Althought there is an option '--depth=x' for users to decide how deep history they can fetch, as the unshallow cloning's depth is INFINITY, we might start with depth x, and the source may be deep enough to give us x right now, but we may want to deepen more than they can offer, and such a user would want to be able to say "I want depth=x now, but make sure they are not shallow". it's hard to find such a x value to make sure they are not shallow.
Teach '--reject-shallow' option to "git clone" to abort as soon as we find out that we are cloning from a shallow repository.
---
builtin/clone.c: add --reject-shallow option
Changes since v1:
* Rename --no-shallow to --reject-shallow
* Enable to reject a non-local clone
* Enable --[no-]reject-shallow from CLI override configuration.
* Add more testcases.
* Reword commit messages and relative documentation.
Changes since v3:
* Add support to reject clone shallow repo over https protocol
* Add testcase to reject clone shallow repo over https:// transport
* Reword commit messages and relative documentation according suggestions from Junio.
Changes since v5:
* camelcase config variable
* warning client that source repo is shallow
* better support ssh:// and git:// protocol v1, v2
Changes since v6:
* use _() for warning/die statement
Changes since v7:
* Clear reviewed-by trailer
* Drop warning() statement
* Reword a few test titles
Changes since v8:
* Use single variable for option and config
* Rename remote_shallow to reject_shallow_remote
* Simplify test cases
Changes since v9:
* Reword commit message
* Use option_reject_shallow and config_reject_shallow
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-865%2FCactusinhand%2Fgit-clone-options-v10
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-865/Cactusinhand/git-clone-options-v10
Pull-Request: https://github.com/gitgitgadget/git/pull/865
Range-diff vs v9:
1: 11043a2344dd ! 1: cacda5a6af07 builtin/clone.c: add --reject-shallow option
@@
## Metadata ##
-Author: lilinchao <[email protected]>
+Author: Li Linchao <[email protected]>
## Commit message ##
builtin/clone.c: add --reject-shallow option
@@ Commit message
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, users should have the option to
- refuse to clone this kind of repository, and may want to exit the
- process immediately without creating any unnecessary files.
+ until they download it to local, we may want to refuse to clone
+ this kind of repository, without creating any unnecessary files.
Althought there is an option '--depth=x' for users to decide how
- deep history they can fetch, but as the unshallow cloning's depth
- is INFINITY, we can't know exactly the minimun 'x' value that can
- satisfy the minimum integrity, so we can't pass 'x' value to --depth,
- and expect this can obtain a complete history of a repository.
+ deep history they can fetch, as the unshallow cloning's depth is
+ INFINITY, we might start with depth x, and the source may be deep
+ enough to give us x right now, but we may want to deepen more than
+ they can offer, and such a user would want to be able to say
+ "I want depth=x now, but make sure they are not shallow".
+ it's hard to find such a x value to make sure they are not shallow.
- In other scenarios, if we have an API that allow us to import external
- repository, and then perform various operations on the repo.
- But if the imported is a shallow one(which is actually possible), it
- will affect the subsequent operations. So we can choose to refuse to
- clone, and let's just import a normal repository.
-
- This patch offers a new option '--reject-shallow' that can reject to
- clone a shallow repository.
+ Teach '--reject-shallow' option to "git clone" to abort as
+ soon as we find out that we are cloning from a shallow
+ repository.
@@ builtin/clone.c: static int option_no_checkout, option_bare, option_mirror, opti
static int option_no_tags;
static int option_shallow_submodules;
+static int option_reject_shallow = -1; /* unspecified */
++static int config_reject_shallow = -1; /* unspecified */
static int deepen;
static char *option_template, *option_depth, *option_since;
static char *option_origin = NULL;
@@ builtin/clone.c: static int git_clone_config(const char *k, const char *v, void
free(remote_name);
remote_name = xstrdup(v);
}
-+ if (!strcmp(k, "clone.rejectshallow") && option_reject_shallow < 0)
-+ option_reject_shallow = git_config_bool(k, v);
++ if (!strcmp(k, "clone.rejectshallow"))
++ config_reject_shallow = git_config_bool(k, v);
+
return git_default_config(k, v, cb);
}
+@@ builtin/clone.c: static int path_exists(const char *path)
+ int cmd_clone(int argc, const char **argv, const char *prefix)
+ {
+ int is_bundle = 0, is_local;
++ int reject_shallow = 0;
+ const char *repo_name, *repo, *work_tree, *git_dir;
+ char *path, *dir, *display_repo = NULL;
+ int dest_exists, real_dest_exists = 0;
+@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
+ */
+ 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
+ * call to git_config, to ensure it overrides all config-based values.
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
if (filter_options.choice)
warning(_("--filter is ignored in local clones; use file:// instead."));
if (!access(mkpath("%s/shallow", path), F_OK)) {
-+ if (option_reject_shallow > 0)
++ if (reject_shallow)
+ die(_("source repository is shallow, reject to clone."));
if (option_local > 0)
warning(_("source repository is shallow, ignoring --local"));
@@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
-+ if (option_reject_shallow > 0)
++ if (reject_shallow)
+ transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
if (option_depth)
transport_set_option(transport, TRANS_OPT_DEPTH,
Documentation/config/clone.txt | 4 ++++ Documentation/git-clone.txt | 7 ++++++- builtin/clone.c | 21 +++++++++++++++++++++ fetch-pack.c | 12 ++++++++---- fetch-pack.h | 1 + t/t5601-clone.sh | 9 +++++++++ t/t5606-clone-options.sh | 27 ++++++++++++++++++++++++++- t/t5611-clone-config.sh | 25 +++++++++++++++++++++++++ transport.c | 4 ++++ transport.h | 4 ++++ 10 files changed, 108 insertions(+), 6 deletions(-)
Documentation/config/clone.txt +4 -0
@@ -2,3 +2,7 @@ clone.defaultRemoteName:: The name of the remote to create when cloning a repository. Defaults to `origin`, and can be overridden by passing the `--origin` command-line 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]
Documentation/git-clone.txt +6 -1
@@ -15,7 +15,7 @@ SYNOPSIS [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] - [--[no-]remote-submodules] [--jobs <n>] [--sparse] + [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter>] [--] <repository> [<directory>]
@@ -149,6 +149,11 @@ objects from the source repository into a pack in the cloned repository. --no-checkout:: 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:: Make a 'bare' Git repository. That is, instead of creating `<directory>` and placing the administrative
builtin/clone.c +21 -0
@@ -50,6 +50,8 @@ static int option_no_checkout, option_bare, option_mirror, option_single_branchstatic int option_local =-1 , option_no_hardlinks, option_shared;static int option_no_tags;static int option_shallow_submodules; +static int option_reject_shallow =-1 ;/* unspecified */ +static int config_reject_shallow =-1 ;/* unspecified */ static int deepen;static char *option_template, *option_depth, *option_since;static char *option_origin =NULL ;
@@ -90,6 +92,8 @@ static struct option builtin_clone_options[] = {OPT__VERBOSITY (&option_verbosity),OPT_BOOL (0 ,"progress" , &option_progress,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,N_ ("don't create a checkout" )), 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); remote_name =xstrdup (v); } +if (!strcmp (k,"clone.rejectshallow" )) + config_reject_shallow =git_config_bool (k, v); +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 is_bundle =0 , is_local; +int reject_shallow =0 ;const char *repo_name, *repo, *work_tree, *git_dir;char *path, *dir, *display_repo =NULL ;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 ); +/* +* 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 * 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)warning (_ ("--filter is ignored in local clones; use file:// instead." ));if (!access (mkpath ("%s/shallow" , path),F_OK )) { +if (reject_shallow) +die (_ ("source repository is shallow, reject to clone." ));if (option_local >0 )warning (_ ("source repository is shallow, ignoring --local" )); 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" ); +if (reject_shallow) +transport_set_option (transport,TRANS_OPT_REJECT_SHALLOW ,"1" );if (option_depth)transport_set_option (transport,TRANS_OPT_DEPTH , option_depth);
fetch-pack.c +8 -4
@@ -1129,9 +1129,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,if (args->deepen)setup_alternate_shallow (&shallow_lock, &alternate_shallow_file,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); -else + }else alternate_shallow_file =NULL ;if (get_pack (args, fd, pack_lockfiles,NULL , sought, nr_sought, &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. */ 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 =setup_temporary_shallow (si->shallow); -else + }else alternate_shallow_file =NULL ; }else { alternate_shallow_file =NULL ;
fetch-pack.h +1 -0
@@ -39,6 +39,7 @@ struct fetch_pack_args { unsigned self_contained_and_connected:1; unsigned cloning:1; unsigned update_shallow:1; + unsigned reject_shallow_remote:1; unsigned deepen:1;/*
t/t5601-clone.sh +9 -0
@@ -759,6 +759,15 @@ test_expect_success 'partial clone using HTTP' ' 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 # test script is only executed when httpd is available and enabled.
t/t5606-clone-options.sh +26 -1
@@ -11,7 +11,8 @@ test_expect_success 'setup' ' mkdir parent && (cd parent && git init && 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' ' git clone parent clone-default-origin &&
t/t5611-clone-config.sh +25 -0
@@ -95,6 +95,31 @@ test_expect_success 'clone -c remote.<remote>.fetch=<refspec> --origin=<name>' ' 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_commit attributes .gitattributes "" && rm -rf child &&
transport.c +4 -0
@@ -236,6 +236,9 @@ static int set_git_option(struct git_transport_options *opts,list_objects_filter_die_if_populated (&opts->filter_options);parse_list_objects_filter (&opts->filter_options, value);return 0 ; + }else if (!strcmp (name,TRANS_OPT_REJECT_SHALLOW )) { + opts->reject_shallow = !!value; +return 0 ; }return 1 ; }
@@ -370,6 +373,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.reject_shallow_remote = transport->smart_options->reject_shallow;if (!data->got_remote_heads) {int i;
transport.h +4 -0
@@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned reject_shallow : 1; unsigned deepen_relative : 1;/* 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 */ #define TRANS_OPT_FOLLOWTAGS "followtags" +/* Reject shallow repo transport */ +#define TRANS_OPT_REJECT_SHALLOW "rejectshallow" +/* Accept refs that may update .git/shallow without --depth */ #define TRANS_OPT_UPDATE_SHALLOW "updateshallow"
base-commit: a65ce7f831aa5fcc596c6d23fcde543d98b39bd7
Signature · 1 line
gitgitgadget