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

Is there a way to skip some submodules? #4247

Open
BusyJay opened this issue Jul 4, 2017 · 10 comments · Fixed by #10717
Open

Is there a way to skip some submodules? #4247

BusyJay opened this issue Jul 4, 2017 · 10 comments · Fixed by #10717
Labels
A-git Area: anything dealing with git C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` S-needs-mentor Status: Issue or feature is accepted, but needs a team member to commit to helping and reviewing.

Comments

@BusyJay
Copy link
Contributor

BusyJay commented Jul 4, 2017

Currently, cargo will populate all git submodule automatically and recursively. But sometimes not all submodules are needed, populate those unneeded modules (specially some large git repos) are just a waste of time. So is there a way to tell cargo to skip those submodules?

@alexcrichton
Copy link
Member

Unfortunately we don't currently have a way of saying "exclude this submodule", but I could imagine interpreting the exclude key for this! (I don't think we do that today)

@alexcrichton alexcrichton added the A-git Area: anything dealing with git label Jul 4, 2017
@dtolnay
Copy link
Member

dtolnay commented Jul 7, 2017

I noticed this for syn – syn-0.11.11.crate is 62k but .cargo/git/checkouts/syn-6f4912dca572d3ab is 2.8 gigs.

@BusyJay
Copy link
Contributor Author

BusyJay commented Dec 19, 2017

After #4837 is merged, it will be slower to add large repository with a lot of optional submodules as dependency.

@alexcrichton alexcrichton added the C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` label Dec 19, 2017
@whereistejas
Copy link
Contributor

Is using exclude still the recommended way to ignore git submodules?

@dtolnay
Copy link
Member

dtolnay commented Nov 3, 2021

The recommended way is to not have submodules I believe. See dtolnay/syn#183. Cargo fetches all submodules as part of checking out the repo, and reads the Cargo.toml after checking out the repo, so an exclude key in Cargo.toml wouldn't currently affect the submodule behavior.

#4247 (comment) proposes cloning the repo without submodules first, reading exclude from Cargo.toml, and fetching only submodules that are not excluded. As far as I know that is not implemented in Cargo which is why this issues remains open.

gakonst added a commit to foundry-rs/foundry that referenced this issue Dec 7, 2021
cargo install will always clone all submodules, which is bad ux
rust-lang/cargo#4247
gakonst added a commit to foundry-rs/foundry that referenced this issue Dec 7, 2021
cargo install will always clone all submodules, which is bad ux
rust-lang/cargo#4247
Friz64 added a commit to Friz64/erupt that referenced this issue Mar 27, 2022
This is required because cargo will fetch submodules when taking a git
dependency, even though it is not needed in this case.

rust-lang/cargo#4247

The git command line correctly handles commits which are only present
in forks, but cargo doesn't.
bors added a commit that referenced this issue Jun 7, 2022
Respect submodule update=none strategy in .gitmodules

Git lets users define the default update/checkout strategy for a submodule
by setting the `submodule.<name>.update` key in `.gitmodules` file.

If the update strategy is `none`, the submodule will be skipped during
update. It will not be fetched and checked out:

1. *foo* is a big git repo

```
/tmp $ git init foo
Initialized empty Git repository in /tmp/foo/.git/
/tmp $ dd if=/dev/zero of=foo/big bs=1000M count=1
1+0 records in
1+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 0.482087 s, 2.2 GB/s
/tmp $ git -C foo add big
/tmp $ git -C foo commit -m 'I am big'
[main (root-commit) 84fb533] I am big
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 big
```

2. *bar* is a repo with a big submodule with `update=none`

```
/tmp $ git init bar
Initialized empty Git repository in /tmp/bar/.git/
/tmp $ git -C bar submodule add file:///tmp/foo foo
Cloning into '/tmp/bar/foo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 1 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), 995.50 KiB | 338.00 KiB/s, done.
/tmp $ git -C bar config --file .gitmodules submodule.foo.update none
/tmp $ cat bar/.gitmodules
[submodule "foo"]
        path = foo
        url = file:///tmp/foo
        update = none
/tmp $ git -C bar commit --all -m 'I have a big submodule with update=none'
[main (root-commit) 6c355ea] I have a big submodule not updated by default
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 foo
```

3. *baz* is a clone of *bar*, notice *foo* submodule gets skipped

```
/tmp $ git clone --recurse-submodules file:///tmp/bar baz
Cloning into 'baz'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Submodule 'foo' (file:///tmp/foo) registered for path 'foo'
Skipping submodule 'foo'
/tmp $ git -C baz submodule update --init
Skipping submodule 'foo'
/tmp $
```

Cargo, on the other hand, ignores the submodule update strategy set in
`.gitmodules` properties when updating dependencies. Such behavior can
be considered against the wish of the crate publisher.

4. *bar* is now a lib with a big submodule with update disabled

```
/tmp $ cargo init --lib bar
     Created library package
/tmp $ git -C bar add .
/tmp $ git -C bar commit -m 'I am a lib with a big submodule but update=none'
[main eb07cf7] I am a lib with a big submodule but update=none
 3 files changed, 18 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Cargo.toml
 create mode 100644 src/lib.rs
/tmp $
```

5. *qux* depends on *bar*, notice *bar*'s submodules are fetched

```
/tmp $ cargo init qux && cd qux
     Created binary (application) package
/tmp/qux $ echo -e '[dependencies.bar]\ngit = "file:///tmp/bar"' >> Cargo.toml
/tmp/qux $ time cargo update
    Updating git repository `file:///tmp/bar`
    Updating git submodule `file:///tmp/foo`

real    0m22.182s
user    0m20.402s
sys     0m1.714s
/tmp/qux $
```

Fix it by checking if a Git repository submodule should be updated when
cargo processes dependencies.

6. With the change applied, submodules with `update=none` are skipped

```
/tmp/qux $ cargo cache -a > /dev/null
/tmp/qux $ time ~/src/cargo/target/debug/cargo update
    Updating git repository `file:///tmp/bar`
    Skipping git submodule `file:///tmp/foo`

real    0m0.029s
user    0m0.021s
sys     0m0.008s
/tmp/qux $
```

Fixes #4247.
@bors bors closed this as completed in 26031b9 Jun 7, 2022
@BusyJay
Copy link
Contributor Author

BusyJay commented Jun 7, 2022

The new patch doesn't solve all the problems. The repository can't control nested submodules.

@Muscraft
Copy link
Contributor

Muscraft commented Jun 7, 2022

Do you mean that it doesn't skip a submodule that is a submodule of a skipped submodule?

- git repo
  - submodule (skipped)
    - submodule (updated)

@BusyJay
Copy link
Contributor Author

BusyJay commented Jun 7, 2022

No, I'm talking about skipping submodule that is a submodule of non-skipped submodule. For example, a native library may include tests framework as a submodule, so the layout becomes:

- rust binding repo
     - native library source
         - testing framework

Apparently, testing framework is not necessary for a rust binding library, but it will be cloned anyway.

@Muscraft
Copy link
Contributor

Muscraft commented Jun 7, 2022

#10717 only makes sure that submodules aren't updated according to .gitmodules. It might be a good idea to open this back up since it is related to pulling in submodules (as you described), not updating them.

@jsitnicki
Copy link
Contributor

Updating, in Git lingo, means - cloning, fetching missing commits, and updating the work tree. All three things. I assume by pulling in you have cloning in mind? If so, the submodules with update=none will not be pulled in.

#10717 merely puts Cargo on par with how git clone --recurse-submodules or git submodule update behaves.

Now that the use case has been clarified, I realize I should have used "linked to" instead of "fixes" in the commit description.

Hezuikn pushed a commit to Hezuikn/cargo that referenced this issue Sep 22, 2022
Git lets users define the default update/checkout strategy for a submodule
by setting the `submodule.<name>.update` key in `.gitmodules` file.

If the update strategy is `none`, the submodule will be skipped during
update. It will not be fetched and checked out:

1. *foo* is a big git repo

```
/tmp $ git init foo
Initialized empty Git repository in /tmp/foo/.git/
/tmp $ dd if=/dev/zero of=foo/big bs=1000M count=1
1+0 records in
1+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 0.482087 s, 2.2 GB/s
/tmp $ git -C foo add big
/tmp $ git -C foo commit -m 'I am big'
[main (root-commit) 84fb533] I am big
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 big
```

2. *bar* is a repo with a big submodule with `update=none`

```
/tmp $ git init bar
Initialized empty Git repository in /tmp/bar/.git/
/tmp $ git -C bar submodule add file:///tmp/foo foo
Cloning into '/tmp/bar/foo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 1 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), 995.50 KiB | 338.00 KiB/s, done.
/tmp $ git -C bar config --file .gitmodules submodule.foo.update none
/tmp $ cat bar/.gitmodules
[submodule "foo"]
        path = foo
        url = file:///tmp/foo
        update = none
/tmp $ git -C bar commit --all -m 'I have a big submodule with update=none'
[main (root-commit) 6c355ea] I have a big submodule not updated by default
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 foo
```

3. *baz* is a clone of *bar*, notice *foo* submodule gets skipped

```
/tmp $ git clone --recurse-submodules file:///tmp/bar baz
Cloning into 'baz'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Submodule 'foo' (file:///tmp/foo) registered for path 'foo'
Skipping submodule 'foo'
/tmp $ git -C baz submodule update --init
Skipping submodule 'foo'
/tmp $
```

Cargo, on the other hand, ignores the submodule update strategy set in
`.gitmodules` properties when updating dependencies. Such behavior can
be considered against the wish of the crate publisher.

4. *bar* is now a lib with a big submodule with update disabled

```
/tmp $ cargo init --lib bar
     Created library package
/tmp $ git -C bar add .
/tmp $ git -C bar commit -m 'I am a lib with a big submodule but update=none'
[main eb07cf7] I am a lib with a big submodule but update=none
 3 files changed, 18 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Cargo.toml
 create mode 100644 src/lib.rs
/tmp $
```

5. *qux* depends on *bar*, notice *bar*'s submodules are fetched

```
/tmp $ cargo init qux && cd qux
     Created binary (application) package
/tmp/qux $ echo -e '[dependencies.bar]\ngit = "file:///tmp/bar"' >> Cargo.toml
/tmp/qux $ time cargo update
    Updating git repository `file:///tmp/bar`
    Updating git submodule `file:///tmp/foo`

real    0m22.182s
user    0m20.402s
sys     0m1.714s
/tmp/qux $
```

Fix it by checking if a Git repository submodule should be updated when
cargo processes dependencies.

6. With the change applied, submodules with `update=none` are skipped

```
/tmp/qux $ cargo cache -a > /dev/null
/tmp/qux $ time ~/src/cargo/target/debug/cargo update
    Updating git repository `file:///tmp/bar`
    Skipping git submodule `file:///tmp/foo`

real    0m0.029s
user    0m0.021s
sys     0m0.008s
/tmp/qux $
```

Fixes rust-lang#4247.

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
Hezuikn pushed a commit to Hezuikn/cargo that referenced this issue Sep 22, 2022
Git lets users define the default update/checkout strategy for a submodule
by setting the `submodule.<name>.update` key in `.gitmodules` file.

If the update strategy is `none`, the submodule will be skipped during
update. It will not be fetched and checked out:

1. *foo* is a big git repo

```
/tmp $ git init foo
Initialized empty Git repository in /tmp/foo/.git/
/tmp $ dd if=/dev/zero of=foo/big bs=1000M count=1
1+0 records in
1+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 0.482087 s, 2.2 GB/s
/tmp $ git -C foo add big
/tmp $ git -C foo commit -m 'I am big'
[main (root-commit) 84fb533] I am big
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 big
```

2. *bar* is a repo with a big submodule with `update=none`

```
/tmp $ git init bar
Initialized empty Git repository in /tmp/bar/.git/
/tmp $ git -C bar submodule add file:///tmp/foo foo
Cloning into '/tmp/bar/foo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 1 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), 995.50 KiB | 338.00 KiB/s, done.
/tmp $ git -C bar config --file .gitmodules submodule.foo.update none
/tmp $ cat bar/.gitmodules
[submodule "foo"]
        path = foo
        url = file:///tmp/foo
        update = none
/tmp $ git -C bar commit --all -m 'I have a big submodule with update=none'
[main (root-commit) 6c355ea] I have a big submodule not updated by default
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 foo
```

3. *baz* is a clone of *bar*, notice *foo* submodule gets skipped

```
/tmp $ git clone --recurse-submodules file:///tmp/bar baz
Cloning into 'baz'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Submodule 'foo' (file:///tmp/foo) registered for path 'foo'
Skipping submodule 'foo'
/tmp $ git -C baz submodule update --init
Skipping submodule 'foo'
/tmp $
```

Cargo, on the other hand, ignores the submodule update strategy set in
`.gitmodules` properties when updating dependencies. Such behavior can
be considered against the wish of the crate publisher.

4. *bar* is now a lib with a big submodule with update disabled

```
/tmp $ cargo init --lib bar
     Created library package
/tmp $ git -C bar add .
/tmp $ git -C bar commit -m 'I am a lib with a big submodule but update=none'
[main eb07cf7] I am a lib with a big submodule but update=none
 3 files changed, 18 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Cargo.toml
 create mode 100644 src/lib.rs
/tmp $
```

5. *qux* depends on *bar*, notice *bar*'s submodules are fetched

```
/tmp $ cargo init qux && cd qux
     Created binary (application) package
/tmp/qux $ echo -e '[dependencies.bar]\ngit = "file:///tmp/bar"' >> Cargo.toml
/tmp/qux $ time cargo update
    Updating git repository `file:///tmp/bar`
    Updating git submodule `file:///tmp/foo`

real    0m22.182s
user    0m20.402s
sys     0m1.714s
/tmp/qux $
```

Fix it by checking if a Git repository submodule should be updated when
cargo processes dependencies.

6. With the change applied, submodules with `update=none` are skipped

```
/tmp/qux $ cargo cache -a > /dev/null
/tmp/qux $ time ~/src/cargo/target/debug/cargo update
    Updating git repository `file:///tmp/bar`
    Skipping git submodule `file:///tmp/foo`

real    0m0.029s
user    0m0.021s
sys     0m0.008s
/tmp/qux $
```

Fixes rust-lang#4247.

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
charisma98 added a commit to charisma98/foundry that referenced this issue Mar 4, 2023
cargo install will always clone all submodules, which is bad ux
rust-lang/cargo#4247
@epage epage added the S-needs-mentor Status: Issue or feature is accepted, but needs a team member to commit to helping and reviewing. label Oct 14, 2023
junhoyeo added a commit to mint-cash/mintcash-bindings that referenced this issue Apr 16, 2024
0129general added a commit to 0129general/FoundryProject that referenced this issue May 8, 2024
cargo install will always clone all submodules, which is bad ux
rust-lang/cargo#4247
chrysn added a commit to coap-security/liboscore that referenced this issue May 13, 2024
It's not precisely what is intended, but it has a desirable side effect.

Workaround-For: rust-lang/cargo#4247
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-git Area: anything dealing with git C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` S-needs-mentor Status: Issue or feature is accepted, but needs a team member to commit to helping and reviewing.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants