Home > Net >  How to switch to another branch while recursively initing submodules
How to switch to another branch while recursively initing submodules

Time:05-19

I have a git repository with several submodules (see an example). Its structure looks like this:

I--A--B <- main
       \
        C <- branch-c
  • Commit A adds a submodule-a
  • Commit B adds a submodule-b
  • Commit C adds a submodule-c on branch branch-c

When I clone the above repo using git clone --recurse-submodules <URL> only the submodule-a and submodule-b submodules get initialised and cloned.

When I then want to check out branch branch-c using git checkout branch-c, the directory for submodule-c gets created, but the submodule itself is not initialised. There is no indication in the command output that some additional steps are needed. Neither git status nor git diff give any hint.

When instead I want to check out branch-c using git checkout --recurse-submodules branch-c I get an error:

fatal: not a git repository: ../../.git/modules/subrepos/subrepo-c
fatal: could not reset submodule index

How do I check out (or switch to) branch branch-c while automatically initialising all submodules?

CodePudding user response:

Your example repository is lacking a branch-c, so it's not a complete MCVE, but it's a good start :)

When I clone the above repo using git clone --recurse-submodules <URL> only the submodule-a and submodule-b submodules get initialised and cloned.

Yes, this is the current behaviour of git clone --recurse-submodules. The submodules are cloned and initialized using an invocation of git submodule update --init --recursive during the checkout phase of git clone, and as such, only submodules recorded in the default branch (or the branch specified using git clone -b <branch>) are cloned and initialized.

When I then want to check out branch branch-c using git checkout branch-c, the directory for submodule-c gets created, but the submodule itself is not initialised. There is no indication in the command output that some additional steps are needed. Neither git status nor git diff give any hint.

Yes, this is unfortunately still the default behaviour of Git. Submodules working trees are not checked out by default by git checkout <branch>. git submodule status (or just git submodule) will show uninitialized submodules with a - prefixed.

When instead I want to check out branch-c using git checkout --recurse-submodules branch-c I get an error:

fatal: not a git repository: ../../.git/modules/subrepos/subrepo-c
fatal: could not reset submodule index

This is a good reflex but unfortunately it does not work in that specific case and leads to this bad UX. git checkout --recurse-submodules <branch> assumes that every submodule recorded in branch-c are already initialized. Since that's not the case here, it errors out because it can't find the .git directory of the submodule. The message could be clearer. What you have to do (the first time you switch to branch-c after cloning your repository) is to check out branch-c non-recursively, and then initialize the submodule:

git checkout branch-c
git submodule update --init --recursive

Then, you will be able to correctly switch between your branches with --recurse-submodules:

git checkout --recurse-submodules main
git checkout --recurse-submodules branch-c
# etc

Note that you can set submodule.recurse in your config to avoid having to use --recurse-submodules all the time.

  • Related