Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the usage of the submodules.recurse parameter on clone #695

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Masmiseim36
Copy link

@Masmiseim36 Masmiseim36 commented Jan 15, 2020

This adds the usage of the submodule.recurse parameter on clone

Changes since v1:

  • Fixed the commit author to match the Signed-off-by line

Changes since v2:

  • Added additional regression tests for checking the --no-recurse-submodules parameter
  • fixed not working --no-recurse-submodules parameter when submodule.recurse option is set
  • fixed invalid setting of “true” to the pathspec

Changes since v3:

  • Using the solution from Junio C Hamano which is tested with the regression tests introduced in V3

@gitgitgadget-git
Copy link

Welcome to GitGitGadget

Hi @Masmiseim36, and welcome to GitGitGadget, the GitHub App to send patch series to the Git mailing list from GitHub Pull Requests.

Please make sure that your Pull Request has a good description, as it will be used as cover letter.

Also, it is a good idea to review the commit messages one last time, as the Git project expects them in a quite specific form:

  • the lines should not exceed 76 columns,
  • the first line should be like a header and typically start with a prefix like "tests:" or "commit:", and
  • the commit messages' body should be describing the "why?" of the change.
  • Finally, the commit messages should end in a Signed-off-by: line matching the commits' author.

It is in general a good idea to await the automated test ("Checks") in this Pull Request before contributing the patches, e.g. to avoid trivial issues such as unportable code.

Contributing the patches

Before you can contribute the patches, your GitHub username needs to be added to the list of permitted users. Any already-permitted user can do that, by adding a comment to your PR of the form /allow. A good way to find other contributors is to locate recent pull requests where someone has been /allowed:

Both the person who commented /allow and the PR author are able to /allow you.

An alternative is the channel #git-devel on the FreeNode IRC network:

<newcontributor> I've just created my first PR, could someone please /allow me? https://github.com/gitgitgadget/git/pull/12345
<veteran> newcontributor: it is done
<newcontributor> thanks!

Once on the list of permitted usernames, you can contribute the patches to the Git mailing list by adding a PR comment /submit.

If you want to see what email(s) would be sent for a /submit request, add a PR comment /preview to have the email(s) sent to you. You must have a public GitHub email address for this.

After you submit, GitGitGadget will respond with another comment that contains the link to the cover letter mail in the Git mailing list archive. Please make sure to monitor the discussion in that thread and to address comments and suggestions (while the comments and suggestions will be mirrored into the PR by GitGitGadget, you will still want to reply via mail).

If you do not want to subscribe to the Git mailing list just to be able to respond to a mail, you can download the mbox from the Git mailing list archive (click the (raw) link), then import it into your mail program. If you use GMail, you can do this via:

curl -g --user "<EMailAddress>:<Password>" \
    --url "imaps://imap.gmail.com/INBOX" -T /path/to/raw.txt

To iterate on your change, i.e. send a revised patch or patch series, you will first want to (force-)push to the same branch. You probably also want to modify your Pull Request description (or title). It is a good idea to summarize the revision by adding something like this to the cover letter (read: by editing the first comment on the PR, i.e. the PR description):

Changes since v1:
- Fixed a typo in the commit message (found by ...)
- Added a code comment to ... as suggested by ...
...

To send a new iteration, just add another PR comment with the contents: /submit.

Need help?

New contributors who want advice are encouraged to join git-mentoring@googlegroups.com, where volunteers who regularly contribute to Git are willing to answer newbie questions, give advice, or otherwise provide mentoring to interested contributors. You must join in order to post or view messages, but anyone can join.

You may also be able to find help in real time in the developer IRC channel, #git-devel on Freenode. Remember that IRC does not support offline messaging, so if you send someone a private message and log out, they cannot respond to you. The scrollback of #git-devel is archived, though.

@gitgitgadget-git
Copy link

There is an issue in commit 4f574cf4b3f8ade0aa928613034157fca90b9696:
Commit checks stopped - the message is too short

@gitgitgadget-git
Copy link

There is an issue in commit 8aabd4c9ecd36f3919c3263dfce092d5466672bc:
Commit checks stopped - the message is too short

@gitgitgadget-git
Copy link

There is an issue in commit bb5b2efc847fd402dfc2399686f8bcb2f5a7d662:
Commit checks stopped - the message is too short

@dscho
Copy link
Member

dscho commented Jan 15, 2020

/allow

@gitgitgadget-git
Copy link

User Masmiseim36 is now allowed to use GitGitGadget.

WARNING: Masmiseim36 has no public email address set on GitHub

Copy link
Member

@dscho dscho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These commits should all be squashed into a single one. The commit message should be improved, in accordance with https://git-scm.com/docs/SubmittingPatches#describe-changes, and the sign-off is required (look at the existing commit history to see the commit message style preferred in the Git project).

t/t7407-submodule-foreach.sh Outdated Show resolved Hide resolved
git rev-parse --resolve-git-dir nested1/nested2/.git &&
git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to do this in a single invocation, and then to compare it to the expected values. Besides, I don't think that it needs to be exhaustive. So I would do this instead:

git -C clone5 rev-parse \
    --resolve-git-dir .git \
    --resolve-git-dir nested1/nested2/nested3/submodule/.git >actual &&
cat >expect <<-EOF &&
.git
$(pwd)/nested1/nested2/nested3/submodule/.git
EOF
test_cmp expect actual

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, don’t get it. I just copied the test for ‘git clone –recursive’. This command should do the identical job like git clone -c submodule.recurse=true’. Why do different tests?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you can improve the style? You also do not need to be so extensive in an essentially slightly repeated test. Testing whether one nested submodule was cloned should be plenty enough.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I will take a closer look. I like to understand the test regression code a bit better first

builtin/clone.c Outdated
{
if (!strcmp(var, "submodule.recurse")) {
option_recurse_submodules.nr = git_config_bool(var, value) ?
1 : option_recurse_submodules.nr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is most likely incorrect, as option_recurse_submodules is a string_list, and increasing the nr without even allocating a corresponding item, let alone initializing it, is most likely causing a crash.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, the Size is used as an indication of submodules active or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what we really want to do is to stay as close to what passing the --recurse-submodules option would have accomplished, which is to add ".", not "true"...

builtin/clone.c Outdated
{
if (!strcmp(var, "submodule.recurse")) {
option_recurse_submodules.nr = git_config_bool(var, value) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does way more than just rename the function. And it still modifies nr without allocating/initializing the item. The correct thing to do here is more likely to be this:

string_list_append(&option_recurse_submodules, ".");

(compare to what recurse_submodules_cb() does when no arg is provided)

@dscho
Copy link
Member

dscho commented Jan 15, 2020

I try to finish the pullrequest #573 from Maddimax.

Thank you for taking on this task!

The changes already look pretty good, but they should be squashed into a single one (use the squash command in an interactive rebase, and while at it, add your sign-off via the --signoff option).

Do make sure to describe the motivation for this change well in the commit message ;-)

@gitgitgadget-git
Copy link

There are issues in commit 332fd226d543d3cdfb8924c271a26994ca3cbc89:
First line of commit message is too long (> 76 columns): clone: respect submodules.recurse config option for automatically clone submodules
The first line must be separated from the rest by an empty line
Commit not signed off

@dscho
Copy link
Member

dscho commented Jan 17, 2020

Please ignore the failing Visual Studio build for now. Your next push should "fix" this by virtue of master being fixed.

It would be good to fix the commit message, though, as the GitGitGadget bot pointed out. Please wrap the paragraphs at <=76 columns/line and leave empty lines between them.

Also, instead of "clone: respect submodules.recurse config option for automatically clone submodules" you could say "clone: respect the submodule.recurse config setting".

Please note that I suggested the submodule.recurse name, which already exists, as opposed to submodules.recurse (note the singular vs plural). As a fun exercise, you could use git blame and/or git log -L ... to find out why it specifically excludes clone. It may have been intentional rather than due to implementation details.

@gitgitgadget-git
Copy link

There are issues in commit 6ca650a55da1c509a186eec0eb26921d6ef0c7bc:
The first line must be separated from the rest by an empty line
Commit not signed off

@dscho
Copy link
Member

dscho commented Jan 17, 2020

The first line must be separated from the rest by an empty line

I see that you broke the first line of the commit message (you really have to look at the commit locally, it is not obvious in GitHub's UI):

clone: respect submodule.recurse config option for automatically clone
submodules

Simplify cloning repositories by making it transparent to the user if
submodules are used. The user doesn’t have to know if he has to add an
extra parameter to get the full project including the linked submodules.

It is done analog to the pull command by using an own config function
instead of using just the default config

Maybe you can think of another way to phrase it so that it gets shorter?

Also, I really think that you are asking to be questioned why the documentation explicitly excludes clone from supporting that config setting. There's got to be some information in the commit log about the documentation or on the Git mailing list about that patch that added this, and it would be good not only to be prepared to field those questions, but to preemptively write about it in the commit message.

Finally, you will still need to sign-off on the patch (easy: call git commit --amend --signoff). Looking at that, I am a bit perplexed by the author/committer information in your commit: the author seems to be "Masmiseim masmiseim@gmx.de" but the committer seems to be "Markus Klein Markus.Klein@sma.de" instead. It would be good to settle on the latter, I think. You can re-set the authorship via git commit --amend --reset-author.

@dscho
Copy link
Member

dscho commented Jan 25, 2020

@Masmiseim36 ping?

@Masmiseim36
Copy link
Author

@Masmiseim36 ping?
Hello,
I’m not gone, just a bit busy, sorry.
I went through some commits regarding clone and submodules and updated the commit comment a bit.
In the moment I’m trying to figure out the internals of the test code. I’m by far not an expert on shell-scripts.
However, I plan to finish this.

@gitgitgadget-git
Copy link

There is an issue in commit 64a70401aaed298029a2f69319d83fbe6399f034:
Commit not signed off

@dscho
Copy link
Member

dscho commented Jan 28, 2020

I restarted the failed test (it failed for unrelated reasons in a flaky test, the re-run should "fix" it).

You will still be required to add your Sign-off, GitGitGadget won't let you send the patch otherwise.

@dscho
Copy link
Member

dscho commented Jan 30, 2020

Hmm. I think the Signed-off-by: line is still incomplete, as it only says "Markus", not "Markus Klein". The reviewers on the Git mailing list won't like that, https://git-scm.com/docs/SubmittingPatches#sign-off specifically states:

Also notice that a real name is used in the Signed-off-by: line. Please don’t hide your real name.

@Masmiseim36
Copy link
Author

Hello dscho,

I’ve extended the “Signed-off-by:” with my full name.

Thanks for the guidance and the feedback. I really appreciate that.

@dscho
Copy link
Member

dscho commented Jan 31, 2020

Looks good to me. I think it's /submit time!

@gitgitgadget-git
Copy link

Error: Could not determine full name of Masmiseim36

@Masmiseim36
Copy link
Author

/submit

@gitgitgadget-git
Copy link

@gitgitgadget-git
Copy link

On the Git mailing list, Johannes Schindelin wrote (reply to this):

  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-864764858-1580591979=:46
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Hi Markus,


On Fri, 31 Jan 2020, Markus Klein via GitGitGadget wrote:

> From: Markus <masmiseim@gmx.de>

This line should probably match...

>
> Simplify cloning repositories with submodules when the option
> submodules.recurse is set by the user. This makes it transparent to the
> user if submodules are used. The user doesn=E2=80=99t have to know if he=
 has to add
> an extra parameter to get the full project including the used submodules=
.
> This makes clone behave identical to other commands like fetch, pull,
> checkout, ... which include the submodules automatically if this option =
is
> set.
>
> It is implemented analog to the pull command by using an own config
> function instead of using just the default config. In contrast to the pu=
ll
> command, the submodule.recurse state is saved as an array of strings as =
it
> can take an optionally pathspec argument which describes which submodule=
s
> should be recursively initialized and cloned. To recursively initialize =
and
> clone all submodules a pathspec of "." has to be used.
> The regression test is simplified compared to the test for "git clone
> --recursive" as the general functionality is already checked there.
>
> Signed-off-by: Markus Klein <masmiseim@gmx.de>

... this line. I.e. you will want to run `git config --global user.name
"Markus Klein"` and then `git commit --amend --reset-author`.

Ciao,
Johannes

> ---
>     Add the usage of the submodules.recurse parameter on clone
>
>     I try to finish the pullrequest #573 from Maddimax. This adds the us=
age
>     of the submodules.recurse parameter on clone
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-69=
5%2FMasmiseim36%2Fdev%2FCloneWithSubmodule-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-695/M=
asmiseim36/dev/CloneWithSubmodule-v1
> Pull-Request: https://github.com/git/git/pull/695
>
>  builtin/clone.c              | 16 +++++++++++++++-
>  t/t7407-submodule-foreach.sh | 11 +++++++++++
>  2 files changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 0fc89ae2b9..21b9d927a2 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -26,6 +26,8 @@
>  #include "dir-iterator.h"
>  #include "iterator.h"
>  #include "sigchain.h"
> +#include "submodule-config.h"
> +#include "submodule.h"
>  #include "branch.h"
>  #include "remote.h"
>  #include "run-command.h"
> @@ -929,6 +931,18 @@ static int path_exists(const char *path)
>  	return !stat(path, &sb);
>  }
>
> +/**
> + * Read config variables.
> + */
> +static int git_clone_config(const char *var, const char *value, void *c=
b)
> +{
> +	if (!strcmp(var, "submodule.recurse") && git_config_bool(var, value)) =
{
> +		string_list_append(&option_recurse_submodules, "true");
> +		return 0;
> +	}
> +	return git_default_config(var, value, cb);
> +}
> +
>  int cmd_clone(int argc, const char **argv, const char *prefix)
>  {
>  	int is_bundle =3D 0, is_local;
> @@ -1103,7 +1117,7 @@ int cmd_clone(int argc, const char **argv, const c=
har *prefix)
>
>  	write_config(&option_config);
>
> -	git_config(git_default_config, NULL);
> +	git_config(git_clone_config, NULL);
>
>  	if (option_bare) {
>  		if (option_mirror)
> diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
> index 6b2aa917e1..44b32f7b27 100755
> --- a/t/t7407-submodule-foreach.sh
> +++ b/t/t7407-submodule-foreach.sh
> @@ -383,6 +383,17 @@ test_expect_success 'use "update --recursive nested=
1" to checkout all submodules
>  		git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.gi=
t
>  	)
>  '
> +test_expect_success 'use "git clone" with submodule.recurse=3Dtrue to c=
heckout all submodules' '
> +	git clone -c submodule.recurse=3Dtrue super clone7 &&
> +	(
> +		git -C clone7 rev-parse --resolve-git-dir .git --resolve-git-dir nest=
ed1/nested2/nested3/submodule/.git >actual &&
> +		cat >expect <<-EOF &&
> +		.git
> +		$(pwd)/clone7/.git/modules/nested1/modules/nested2/modules/nested3/mo=
dules/submodule
> +		EOF
> +		test_cmp expect actual
> +	)
> +'
>
>  test_expect_success 'command passed to foreach retains notion of stdin'=
 '
>  	(
>
> base-commit: d0654dc308b0ba76dd8ed7bbb33c8d8f7aacd783
> --
> gitgitgadget
>

--8323328-864764858-1580591979=:46--

@Masmiseim36
Copy link
Author

Masmiseim36 commented Feb 3, 2020 via email

@dscho
Copy link
Member

dscho commented Feb 4, 2020

Thanks for the hint. I’ve fixed this Best Regards Markus

This was the only information in that otherwise garbled reply, right?

@dscho
Copy link
Member

dscho commented Feb 4, 2020

Thanks for the hint. I’ve fixed this Best Regards Markus

I was able to verify this by looking at this: https://github.com/git/git/commit/a59ca4e27b7879f07d99d56cb972761e59714731.patch

This was the only information in that otherwise garbled reply, right?

If so, please note that nobody on the Git mailing list saw your reply nor your change.

To send another iteration of this patch, please use GitGitGadget again: add a comment consisting of /submit and nothing else.

Before that, you will want to edit the initial comment (which will be sent as a sort of cover letter, embedded within the single-patch mail) to say something along these lines:

Changes since v1:

  • Fixed the commit author.

@Masmiseim36
Copy link
Author

Thanks for the hint. I’ve fixed this Best Regards Markus

This was the only information in that otherwise garbled reply, right?

Sorry for the confusion, Maybe I should try a different E-Mail client.
Yes, that was all the information

@Masmiseim36
Copy link
Author

/submit

@gitgitgadget-git
Copy link

@dscho
Copy link
Member

dscho commented Feb 5, 2020

For what it's worth: by "initial comment", I meant the first comment on the PR, i.e. the PR description, not the commit message...

@gitgitgadget-git
Copy link

On the Git mailing list, Johannes Schindelin wrote (reply to this):

  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-1982473641-1580899056=:46
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Hi Markus,

On Tue, 4 Feb 2020, Markus Klein via GitGitGadget wrote:

> From: Markus Klein <masmiseim@gmx.de>
>
> Simplify cloning repositories with submodules when the option
> submodules.recurse is set by the user. This makes it transparent to the
> user if submodules are used. The user doesn=E2=80=99t have to know if he=
 has to add
> an extra parameter to get the full project including the used submodules=
.
> This makes clone behave identical to other commands like fetch, pull,
> checkout, ... which include the submodules automatically if this option =
is
> set.
>
> It is implemented analog to the pull command by using an own config
> function instead of using just the default config. In contrast to the pu=
ll
> command, the submodule.recurse state is saved as an array of strings as =
it
> can take an optionally pathspec argument which describes which submodule=
s
> should be recursively initialized and cloned. To recursively initialize =
and
> clone all submodules a pathspec of "." has to be used.
> The regression test is simplified compared to the test for "git clone
> --recursive" as the general functionality is already checked there.
>
> Changes since v1:
> * Fixed the commit author to match the Signed-off-by line

This changelog should go...

>
> Signed-off-by: Markus Klein <masmiseim@gmx.de>
> ---

... after the `---`. I.e. it should go into the PR description (which is
the first comment on the PR) instead of the commit message.

Ciao,
Johannes

>     Add the usage of the submodules.recurse parameter on clone
>
>     I try to finish the pullrequest #573 from Maddimax. This adds the us=
age
>     of the submodules.recurse parameter on clone
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-69=
5%2FMasmiseim36%2Fdev%2FCloneWithSubmodule-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-695/M=
asmiseim36/dev/CloneWithSubmodule-v2
> Pull-Request: https://github.com/git/git/pull/695
>
> Range-diff vs v1:
>
>  1:  7fa8d19faf ! 1:  c75835268a clone: use submodules.recurse option fo=
r automatically clone submodules
>      @@ -1,4 +1,4 @@
>      -Author: Markus <masmiseim@gmx.de>
>      +Author: Markus Klein <masmiseim@gmx.de>
>
>           clone: use submodules.recurse option for automatically clone s=
ubmodules
>
>      @@ -19,6 +19,9 @@
>           The regression test is simplified compared to the test for "gi=
t clone
>           --recursive" as the general functionality is already checked t=
here.
>
>      +    Changes since v1:
>      +    * Fixed the commit author to match the Signed-off-by line
>      +
>           Signed-off-by: Markus Klein <masmiseim@gmx.de>
>
>        diff --git a/builtin/clone.c b/builtin/clone.c
>
>
>  builtin/clone.c              | 16 +++++++++++++++-
>  t/t7407-submodule-foreach.sh | 11 +++++++++++
>  2 files changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 0fc89ae2b9..21b9d927a2 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -26,6 +26,8 @@
>  #include "dir-iterator.h"
>  #include "iterator.h"
>  #include "sigchain.h"
> +#include "submodule-config.h"
> +#include "submodule.h"
>  #include "branch.h"
>  #include "remote.h"
>  #include "run-command.h"
> @@ -929,6 +931,18 @@ static int path_exists(const char *path)
>  	return !stat(path, &sb);
>  }
>
> +/**
> + * Read config variables.
> + */
> +static int git_clone_config(const char *var, const char *value, void *c=
b)
> +{
> +	if (!strcmp(var, "submodule.recurse") && git_config_bool(var, value)) =
{
> +		string_list_append(&option_recurse_submodules, "true");
> +		return 0;
> +	}
> +	return git_default_config(var, value, cb);
> +}
> +
>  int cmd_clone(int argc, const char **argv, const char *prefix)
>  {
>  	int is_bundle =3D 0, is_local;
> @@ -1103,7 +1117,7 @@ int cmd_clone(int argc, const char **argv, const c=
har *prefix)
>
>  	write_config(&option_config);
>
> -	git_config(git_default_config, NULL);
> +	git_config(git_clone_config, NULL);
>
>  	if (option_bare) {
>  		if (option_mirror)
> diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
> index 6b2aa917e1..44b32f7b27 100755
> --- a/t/t7407-submodule-foreach.sh
> +++ b/t/t7407-submodule-foreach.sh
> @@ -383,6 +383,17 @@ test_expect_success 'use "update --recursive nested=
1" to checkout all submodules
>  		git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.gi=
t
>  	)
>  '
> +test_expect_success 'use "git clone" with submodule.recurse=3Dtrue to c=
heckout all submodules' '
> +	git clone -c submodule.recurse=3Dtrue super clone7 &&
> +	(
> +		git -C clone7 rev-parse --resolve-git-dir .git --resolve-git-dir nest=
ed1/nested2/nested3/submodule/.git >actual &&
> +		cat >expect <<-EOF &&
> +		.git
> +		$(pwd)/clone7/.git/modules/nested1/modules/nested2/modules/nested3/mo=
dules/submodule
> +		EOF
> +		test_cmp expect actual
> +	)
> +'
>
>  test_expect_success 'command passed to foreach retains notion of stdin'=
 '
>  	(
>
> base-commit: d0654dc308b0ba76dd8ed7bbb33c8d8f7aacd783
> --
> gitgitgadget
>

--8323328-1982473641-1580899056=:46--

@gitgitgadget-git
Copy link

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Markus Klein via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Markus Klein <masmiseim@gmx.de>
>
> Simplify cloning repositories with submodules when the option
> submodules.recurse is set by the user. This makes it transparent to the
> user if submodules are used. The user doesn�t have to know if he has to add
> an extra parameter to get the full project including the used submodules.
> This makes clone behave identical to other commands like fetch, pull,
> checkout, ... which include the submodules automatically if this option is
> set.

I am not sure if it is even a good idea to make clone behave
identically to fetch and pull.  We cannot escape from the fact that
the initial cloning of the top-level superproject is a special
event---we do not even have a place to put the configuration
specific to that superproject (e.g. which submodules are good ones
to clone by default) before that happens.

You misspelt "submodule.recurse" everywhere in the log message, by
the way, even though the code seems to react to the right variable.

> It is implemented analog to the pull command by using an own config
> function instead of using just the default config. 

I am not sure if this is worth saying, but it is not incorrect per-se.

> In contrast to the pull
> command, the submodule.recurse state is saved as an array of strings as it
> can take an optionally pathspec argument which describes which submodules
> should be recursively initialized and cloned.

Sorry, but I do not think I get this part at all.  Your callback
seems to add a fixed string "true" to option_recurse_submodules
string list as many times as submodule.recurse variable is defined
in various configuration files.  Does anybody count how many and
react differently?  You mention "pathspec" here, but how does one
specify a pathspec beforehand (remember, this is clone and there is
no superproject repository or its per-repository configuration file
yet before we clone it)?

> To recursively initialize and
> clone all submodules a pathspec of "." has to be used.
> The regression test is simplified compared to the test for "git clone
> --recursive" as the general functionality is already checked there.

Documentation/config/submodule.txt says submodule.recurse says

    Specifies if commands recurse into submodules by default. This
    applies to all commands that have a `--recurse-submodules`
    option, except `clone`.  Defaults to false.

so I take that the value must be a boolean.  So I am lost what
pathspec you are talking about here.

> +/**
> + * Read config variables.
> + */

That's a fairly useless comment that does not say more than what the
name of the function already tells us X-<.

> +static int git_clone_config(const char *var, const char *value, void *cb)
> +{
> +	if (!strcmp(var, "submodule.recurse") && git_config_bool(var, value)) {
> +		string_list_append(&option_recurse_submodules, "true");
> +		return 0;

The breakage of this is not apparent, but this is misleading.  If
submodule.recurse is set to a value that git_config_bool() would say
"false", the if statement is skipped, and you end up calling
git_default_config() with "submodule.recurse", even though you are
supposed to have already dealt with the setting.

	if (!strcmp(var, "submodule.recurse")) {
		if (git_config_bool(var, value))
			...
		return 0; /* done with the variable either way */
	}

is more appropriate.  I still do not know what this code is trying
to do by appending "true" as many times as submodule.recurse appears
in the configuration file(s), though.

When given from the command line, i.e.

	git clone --no-recurse-submodules ...
	git clone --recurse-submodules    ...
	git clone --recurse-submodules=<something> ...

recurse_submodules_cb() reacts to them by

 (1) clearing what have been accumulated so far,
 (2) appending the match-all "." pathspec, and
 (3) appending the <something> string 

to option_recurse_submodules string list.  But given that
submodule.recurse is not (and will not be without an involved
transition plan) a pathspec but merely a boolean, I would think
appending hardcoded string constant "true" makes little sense.
After sorting the list, these values become values of the
submodule.active configuration variable whose values are pathspec
elements in cmd_clone(); see the part of the code before it makes a
call to init_db().

So, I would sort-of understand if you pretend --recurse-submodules
was given from the command line when submodule.recurse is set to
true (which would mean that you'd append "." to the string list).
But I do not understand why appending "true" is a good thing at all
here.

Another thing I noticed.

If you have "[submodule] recurse" in your $HOME/.gitconfig, you'd
want to be able to countermand from the command line with

    git clone --no-recurse-submodules ...

so that the clone would not go recursive.  And that should be
tested.  

You'd also want the opposite, i.e. with "[submodule] recurse=no" in
your $HOME/.gitconfig and running

    git clone --recurse-submodules ...

should countermand the configuration.

Thanks.

> +test_expect_success 'use "git clone" with submodule.recurse=true to checkout all submodules' '
> +	git clone -c submodule.recurse=true super clone7 &&
> +	(
> +		git -C clone7 rev-parse --resolve-git-dir .git --resolve-git-dir nested1/nested2/nested3/submodule/.git >actual &&
> +		cat >expect <<-EOF &&
> +		.git
> +		$(pwd)/clone7/.git/modules/nested1/modules/nested2/modules/nested3/modules/submodule
> +		EOF
> +		test_cmp expect actual
> +	)
> +'

@gitgitgadget-git
Copy link

On the Git mailing list, Johannes Schindelin wrote (reply to this):

Hi Junio,

On Thu, 6 Feb 2020, Junio C Hamano wrote:

> "Markus Klein via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > +static int git_clone_config(const char *var, const char *value, void *cb)
> > +{
> > +	if (!strcmp(var, "submodule.recurse") && git_config_bool(var, value)) {
> > +		string_list_append(&option_recurse_submodules, "true");
> > +		return 0;
>
> The breakage of this is not apparent, but this is misleading.  If
> submodule.recurse is set to a value that git_config_bool() would say
> "false", the if statement is skipped, and you end up calling
> git_default_config() with "submodule.recurse", even though you are
> supposed to have already dealt with the setting.
>
> 	if (!strcmp(var, "submodule.recurse")) {
> 		if (git_config_bool(var, value))
> 			...
> 		return 0; /* done with the variable either way */
> 	}
>
> is more appropriate.

Good catch, and I think you will have to do even more: in the "else" case,
it is possible that the user overrode a `submodule.recurse` from the
system config in their user-wide config, so we must _undo_ the
`string_list_append().

Further, it is probably not a good idea to append "true" _twice_ if
multiple configs in the chain specify `submodule.recurse = true`.

> I still do not know what this code is trying to do by appending "true"
> as many times as submodule.recurse appears in the configuration file(s),
> though.
>
> When given from the command line, i.e.
>
> 	git clone --no-recurse-submodules ...
> 	git clone --recurse-submodules    ...
> 	git clone --recurse-submodules=<something> ...
>
> recurse_submodules_cb() reacts to them by
>
>  (1) clearing what have been accumulated so far,
>  (2) appending the match-all "." pathspec, and
>  (3) appending the <something> string
>
> to option_recurse_submodules string list.  But given that
> submodule.recurse is not (and will not be without an involved
> transition plan) a pathspec but merely a boolean, I would think
> appending hardcoded string constant "true" makes little sense.
> After sorting the list, these values become values of the
> submodule.active configuration variable whose values are pathspec
> elements in cmd_clone(); see the part of the code before it makes a
> call to init_db().

Indeed, I think I even pointed out that "true" is not an appropriate value
to use here: https://github.com/git/git/pull/695/#discussion_r367866708

Ciao,
Dscho

@gitgitgadget-git
Copy link

On the Git mailing list, Junio C Hamano wrote (reply to this):

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

>> 	if (!strcmp(var, "submodule.recurse")) {
>> 		if (git_config_bool(var, value))
>> 			...
>> 		return 0; /* done with the variable either way */
>> 	}
>>
>> is more appropriate.
>
> Good catch, and I think you will have to do even more: in the "else" case,
> it is possible that the user overrode a `submodule.recurse` from the
> system config in their user-wide config, so we must _undo_ the
> `string_list_append().

Yeah, I tend to agree that submodule.recurse should not be made into
a multi-valued fields with this change; it should stay to be the
usual last-one-wins single boolean.

> Further, it is probably not a good idea to append "true" _twice_ if
> multiple configs in the chain specify `submodule.recurse = true`.

The user of this list in cmd_clone() first sorts and dedups, so
appending the same is OK, even though it may appear sloppy.

@gitgitgadget-git
Copy link

On the Git mailing list, Junio C Hamano wrote (reply to this):

Junio C Hamano <gitster@pobox.com> writes:

> So, I would sort-of understand if you pretend --recurse-submodules
> was given from the command line when submodule.recurse is set to
> true (which would mean that you'd append "." to the string list).
> But I do not understand why appending "true" is a good thing at all
> here.
>
> Another thing I noticed.
>
> If you have "[submodule] recurse" in your $HOME/.gitconfig, you'd
> want to be able to countermand from the command line with
>
>     git clone --no-recurse-submodules ...
>
> so that the clone would not go recursive.  And that should be
> tested.  
>
> You'd also want the opposite, i.e. with "[submodule] recurse=no" in
> your $HOME/.gitconfig and running
>
>     git clone --recurse-submodules ...
>
> should countermand the configuration.


Totally untested, but just to illustrate the approach, here is a
sample patch to implement "Pretend --recurse-submodules=. is set on
the command line when submodule.recurse is set (in the 'last one
wins' sense) and there is no --recurse-submodules command line
option."  It should outline the right interactions between the
command line options and configuration variable, like allowing "git
clone --no-recurse-submodules" to defeat submodule.recurse
configuration.

Not that I agree that "[submodules] recurse" set in the
$HOME/.gitconfig should affect "git clone".  It is merely to
illustrate how it could be done, if it were a good idea.

 builtin/clone.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 0fc89ae2b9..163803d89e 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -32,6 +32,7 @@
 #include "connected.h"
 #include "packfile.h"
 #include "list-objects-filter-options.h"
+#include "submodule.h"
 
 /*
  * Overall FIXMEs:
@@ -71,6 +72,8 @@ static struct list_objects_filter_options filter_options;
 static struct string_list server_options = STRING_LIST_INIT_NODUP;
 static int option_remote_submodules;
 
+static int recurse_submodules_option_given;
+
 static int recurse_submodules_cb(const struct option *opt,
 				 const char *arg, int unset)
 {
@@ -81,7 +84,7 @@ static int recurse_submodules_cb(const struct option *opt,
 	else
 		string_list_append((struct string_list *)opt->value,
 				   (const char *)opt->defval);
-
+	recurse_submodules_option_given = 1;
 	return 0;
 }
 
@@ -929,6 +932,13 @@ static int path_exists(const char *path)
 	return !stat(path, &sb);
 }
 
+static int git_clone_config(const char *var, const char *value, void *cb)
+{
+	if (starts_with(var, "submodule."))
+		return git_default_submodule_config(var, value, NULL);
+	return git_default_config(var, value, cb);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
 	int is_bundle = 0, is_local;
@@ -1103,7 +1113,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 	write_config(&option_config);
 
-	git_config(git_default_config, NULL);
+	git_config(git_clone_config, NULL);
+	if (!recurse_submodules_option_given && should_update_submodules())
+		string_list_append(&option_recurse_submodules, ".");
 
 	if (option_bare) {
 		if (option_mirror)

@gitgitgadget-git
Copy link

On the Git mailing list, wrote (reply to this):

> "Markus Klein via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 
> > From: Markus Klein <masmiseim@gmx.de>
> >
> > Simplify cloning repositories with submodules when the option 
> > submodules.recurse is set by the user. This makes it transparent to 
> > the user if submodules are used. The user doesn�t have to know if he 
> > has to add an extra parameter to get the full project including the used submodules.
> > This makes clone behave identical to other commands like fetch, pull, 
> > checkout, ... which include the submodules automatically if this 
> > option is set.
> 
> I am not sure if it is even a good idea to make clone behave identically to fetch and pull. 
> We cannot escape from the fact that the initial cloning of the top-level superproject is a special
> event---we do not even have a place to put the configuration specific to that superproject
> (e.g. which submodules are good ones to clone by default) before that happens.

It behaves only identical if the option "submodule.recurse" is set in the global .gitconfig. So, it is optional for people who know what they do. For people which use submodules heavily, this is very useful.

For the case where you don't like to get all submodules but have this option set, you can disable it via --no-recurse-submodules

> 
> You misspelt "submodule.recurse" everywhere in the log message, by the way, even though the code seems
> to react to the right variable.
> 
> > It is implemented analog to the pull command by using an own config 
> > function instead of using just the default config.
> 
> I am not sure if this is worth saying, but it is not incorrect per-se.
> 
> > In contrast to the pull
> > command, the submodule.recurse state is saved as an array of strings 
> > as it can take an optionally pathspec argument which describes which 
> > submodules should be recursively initialized and cloned.
> 
> Sorry, but I do not think I get this part at all.  Your callback seems to add a fixed string "true"
> to option_recurse_submodules string list as many times as submodule.recurse variable is defined in
> various configuration files.  Does anybody count how many and react differently?  You mention "pathspec"
> here, but how does one specify a pathspec beforehand (remember, this is clone and there is no superproject
> repository or its per-repository configuration file yet before we clone it)?

I'm so sorry for the confusing with the true. This is definitely wrong. Johannes already pointed this out to me and I had already fixed it. Shame on me, as I had uploaded an old version :-(

> 
> > To recursively initialize and
> > clone all submodules a pathspec of "." has to be used.
> > The regression test is simplified compared to the test for "git clone 
> > --recursive" as the general functionality is already checked there.
> 
> Documentation/config/submodule.txt says submodule.recurse says
> 
>     Specifies if commands recurse into submodules by default. This
>     applies to all commands that have a `--recurse-submodules`
>     option, except `clone`.  Defaults to false.
> 
> so I take that the value must be a boolean.  So I am lost what pathspec you are talking about here.
> 
> > +/**
> > + * Read config variables.
> > + */
> 
> That's a fairly useless comment that does not say more than what the name of the function already tells us X-<.

True, this was copy'pasted from the pull implementation. So it should be useless there also.

> 
> > +static int git_clone_config(const char *var, const char *value, void 
> > +*cb) {
> > +	if (!strcmp(var, "submodule.recurse") && git_config_bool(var, value)) {
> > +		string_list_append(&option_recurse_submodules, "true");
> > +		return 0;
> 
> The breakage of this is not apparent, but this is misleading.  If submodule.recurse is set to a value
> that git_config_bool() would say "false", the if statement is skipped, and you end up calling
> git_default_config() with "submodule.recurse", even though you are supposed to have already dealt with
> the setting.
> 
> 	if (!strcmp(var, "submodule.recurse")) {
> 		if (git_config_bool(var, value))
> 			...
> 		return 0; /* done with the variable either way */
> 	}
> 
> is more appropriate.  I still do not know what this code is trying to do by appending "true" as many
> times as submodule.recurse appears in the configuration file(s), though.
> 
> When given from the command line, i.e.
> 
> 	git clone --no-recurse-submodules ...
> 	git clone --recurse-submodules    ...
> 	git clone --recurse-submodules=<something> ...
> 
> recurse_submodules_cb() reacts to them by
> 
>  (1) clearing what have been accumulated so far,
>  (2) appending the match-all "." pathspec, and
>  (3) appending the <something> string 
> 
> to option_recurse_submodules string list.  But given that submodule.recurse is not (and will not be without
> an involved transition plan) a pathspec but merely a boolean, I would think appending hardcoded string
> constant "true" makes little sense.
> After sorting the list, these values become values of the submodule.active configuration variable whose
> values are pathspec elements in cmd_clone(); see the part of the code before it makes a call to init_db().
> 
> So, I would sort-of understand if you pretend --recurse-submodules was given from the command line when
> submodule.recurse is set to true (which would mean that you'd append "." to the string list).
> But I do not understand why appending "true" is a good thing at all here.
> 
> Another thing I noticed.
> 
> If you have "[submodule] recurse" in your $HOME/.gitconfig, you'd want to be able to countermand
> from the command line with
> 
>     git clone --no-recurse-submodules ...
> 
> so that the clone would not go recursive.  And that should be tested.  
> 
> You'd also want the opposite, i.e. with "[submodule] recurse=no" in your $HOME/.gitconfig and running
> 
>     git clone --recurse-submodules ...
> 
> should countermand the configuration.

Thanks for the hint. I added this tests, and it was very helpful, as it pointed out, that the disabling via --no-recurse-submodules was not working.

> 
> Thanks.
> 
> > +test_expect_success 'use "git clone" with submodule.recurse=true to checkout all submodules' '
> > +	git clone -c submodule.recurse=true super clone7 &&
> > +	(
> > +		git -C clone7 rev-parse --resolve-git-dir .git --resolve-git-dir nested1/nested2/nested3/submodule/.git >actual &&
> > +		cat >expect <<-EOF &&
> > +		.git
> > +		$(pwd)/clone7/.git/modules/nested1/modules/nested2/modules/nested3/modules/submodule
> > +		EOF
> > +		test_cmp expect actual
> > +	)
> > +'

Thanks for the feedback


@Masmiseim36
Copy link
Author

/submit

@gitgitgadget-git
Copy link

@dscho
Copy link
Member

dscho commented Apr 13, 2020

@Masmiseim36 I saw that Junio offered a demo patch; did you end up using that? In any case, what is the status of this patch?

Simplify cloning repositories with submodules when the option
submodule.recurse is set by the user. This makes it transparent to the
user if submodules are used. The user doesn’t have to know if he has to add
an extra parameter to get the full project including the used submodules.
This makes clone behave identical to other commands like fetch, pull,
checkout, ... which include the submodules automatically if this option is
set.

It is implemented analog to the pull command by using an own config
function instead of using just the default config. In contrast to the pull
command, the submodule.recurse state is saved in addition as an array of
strings as it can take an optionally pathspec argument which describes
which submodules should be recursively initialized and cloned. To
recursively initialize and clone all submodules a pathspec of "." has to
be used.
The regression test is simplified compared to the test for "git clone
--recursive" as the general functionality is already checked there.

Signed-off-by: Markus Klein <masmiseim@gmx.de>
@Masmiseim36
Copy link
Author

/submit

@gitgitgadget-git
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants