Reputation: 415
I have a parent repository that has a submodule within it. If I look on the remote side, I can see that the commit ID pointed to by the submodule is 862e0c4e
. This was recently updated to point to that commit ID.
I have a local copy of this parent repository with the submodule already checked out. However my local copy of the parent repository is old and thus the submodule checked out is pointing to a different commit ID. If I run git status
on the submodule on my local copy then it outputs the following: HEAD detached from 475d0b3
. This is understandable since this is an old copy of the repository.
I have already set my git config parameter submodule.recurse
to true
, so my expectation is that if I run git pull
on the parent repository, it will pull all the changes made to the parent repository, including checking out the correct version of the submodule. However after I run git pull
on the parent repository, the submodule does not change. It continues to point to the old commit ID.
I also tried running the command git pull --recurse-submodules
. No change though, as the submodule continues to point to the old commit ID.
If I run git submodule update --init
, then the submodule will check out the correct version and the commit ID will be updated.
Is my expectation of setting submodule.recurse=true
incorrect? Is there no way for the submodule to update the commit ID it's pointing to automatically when running git pull
?
Upvotes: 0
Views: 3127
Reputation: 488193
Submodules are always in detached-HEAD mode. Well ... not always always, but that's entirely normal. To get the superproject Git to update the submodule Git—i.e., to pick a new commit hash ID for detached HEAD mode in the submodule—you must convince the superproject Git that it is time to:
(cd sub/module && git switch --detach <hash>)
The hash ID provided here is stored as what Git calls a gitlink, in each commit in the superproject. You can see this gitlink in git ls-files --stage
output for instance.
The submodule.recurse=true
or git pull --recurse-submodules
flags work by noticing if and when the gitlink hash ID changes in the superproject's index / staging-area. If and when this hash ID changes, the superproject Git will do the:
(cd sub/module && git switch --detach <new-hash>)
operation. Otherwise, it won't. Among other things, this means that once you have updated the superproject itself without updating the submodule (so that the hash ID stored in the index matches that in a newer commit, but not that checked out in the submodule), no further "update the superproject" operation results in a change, unless the update brings in a new commit with yet another new stored hash ID.
The git submodule update
command is an explicit way to have the superproject Git go through the current commit / index, find all the gitlinks therein, and run the same kind of command, with the chosen hash ID, in each submodule. So, manually running it does the trick.
Note that adding --remote
to git submodule update
changes where the superproject gets a hash ID. The rest of the process is unchanged: the superproject Git still pokes along through the index, looking for gitlinks. But, having found a gitlink for sub/module
, the superproject Git doesn't read the hash ID from the gitlink. Now, instead, it does:
(cd sub/module && git fetch)
which causes the submodule repository to be updated from its remote, and then:
(cd sub/module && git rev-parse <branch-name>)
where the branch-name
part comes out of the branch
setting for that submodule. The branch setting comes from .git/config
, if present, or from .gitmodules
if not. Only the git submodule update
command actually does this; the --recurse
or recurse=true
options never do that.
As you're seeing, submodules are pretty brittle. People sometimes call them sob-modules, for good reason. There are numerous workarounds, including the repo
scripts that Google wrote; none are really satisfactory.
Upvotes: 1