2

I have a project where I have checked out the main branch, which has 2 submodules: vendor/foo and vendor/bar. If I create a worktree for a feature branch with git worktree add ../feature feature, this worktree will not have any of those submodules cloned.

If I then go into that worktree and git submodule update --init, this will re-download all of those submodules, which (particularly in the case of large projects with long histories) wastes a bunch of disk space and causes substantial network traffic.

Is there a way to re-use the existing clones in the main worktree?

3
  • git worktree is incompatible with submodules. Commented Nov 21 at 10:44
  • That document isn't entirely correct and is partially out of date Commented Nov 22 at 22:35
  • (currently, removing or moving worktrees with submodules doesn't work - you need to deinit the submodules first and delete their confoguration - but it does work) Commented Nov 22 at 22:37

1 Answer 1

3

This can be done by using the alternates mechanism for git repositories, which allows one git repository to reference the objects stored in another. Note that, as warned in [the manual for git-clone](https://git-scm.com/docs/git-clone)'s notes on --shared, you must take care not to perform operations (such as deleting a branch in the main submodule) that would create unreachable (from branches or HEAD) commits which are still referenced in the worktree (although, since --reference copies some objects, this is much less of a risk).

Git submodule updates allow for a --reference <path> option, just like the one that can be passed to git clone, which will tell git to set up <path> as an alternate source of objects that is checked in preference to the repository URL. This option will only have an effect when cloning, but since this new worktree hasn't cloned these submodules yet, it will take effect.

To check out all submodules by reference, you could use a loop like this. Note that, before doing any cloning, we do a git submodule init so that all the expected metadata is in place.

# In the newly-created worktree - in your example, ../feature
git submodule init
for submodule in $(git config get --file=.gitmodules --all --regexp path); do
    git submodule update --reference "../main/$submodule" "$submodule"
done

Note that this doesn't handle recursive submodules - for that, you'll want to repeat this process within each of those sub-repositories.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.