git clone --no-checkout myreop
cd myrepo
git checkout branch001
git submodule update --init
# all good
cd ..; mv myrepo myrepo.backup
git clone --no-checkout myrepo
git checkout branch002
git submodule update --init
# all good
All good even though the submodule repo address changed between branch001 and branch002.
I can expect this to work because .git/config
has been deleted by cloning branch002 into
an empty directory. But, alternatively, I could also have deleted the submodule entries in .git/config
with the git submodule deinit
command as follows (it does more but I dont think this is relevant here):
git clone --no-checkout myreop
cd myrepo
git checkout branch001
git submodule update --init
git checkout branch002
# the .gitmodules file now has the correct changed submodule url but the
# .git/config file has the previous one which is not in sync with .gitmodules
git submodule deinit -f --all
# .gitmodules is unchanged, still correct.
# .git/config submodule entries are now deleted as I expected, which is good
git submodule update --init
# .gitmodules still unchanged and correct
# .git/config is now in sync with .gitmodules again
But surprisingly the last command fails nonetheless:
fatal: git upload-pack: not our ref 11ba32ee3c7104f9ce614a393b02624ce09bdcda
fatal: remote error: upload-pack: not our ref 11ba32ee3c7104f9ce614a393b02624ce09bdcda
fatal: Fetched in submodule path 'modulpath', but it did not contain 11ba32ee3c7104f9ce614a393b02624ce09bdcda. Direct fetching of that commit failed.
Looks like the old_submodule_repo is still stored somewhere. So I make a check:
$ find . -type f -exec grep -l "new_submodule_repo" {} \;
./.git/logs/HEAD
./.git/logs/refs/heads/master
./.git/logs/refs/remotes/origin/HEAD
./.git/config
./.gitlab-ci.yml
./.gitmodules
$ find . -type f -exec grep -l "old_submodule_repo" {} \;
# nothing
Ok, I found the solution: git submodule sync
instead of git submodule deinit
.
But I still wonder where git has stored the old submodule url and why the submodule origin was pointing there even though .git/config
had the correct url for origin.
When I say git set-url origin ...
then I expect this to be reflected in the .git/config
file and honored. If I make the change to the .git/config
file directly I also expect this to be honored. And it is honored in both cases. But with submodules things seem not to be the same.
So my questions are:
git submodule deinit
not reset the submodule url regardless the fact that git submodule sync
does the job more conveniently without deleting the whole submodule folder?.git/config
?git submodule deinit -f --all
does not delete the upload pack of the submodule?Looks like the old_submodule_repo is still stored somewhere. So I make a check:
$ find . -type f -exec grep -l "new_submodule_repo" {} \; ./.git/logs/HEAD ./.git/logs/refs/heads/master ./.git/logs/refs/remotes/origin/HEAD ./.git/config ./.gitlab-ci.yml ./.gitmodules $ find . -type f -exec grep -l "old_submodule_repo" {} \; # nothing
The second command should have found ./.git/modules/modulpath/config
since this is where the remote.origin.url
config for the submodule remote is ultimately stored. I don't know why your invocation does not find it (it works for me). Maybe you have a non-standard setup ?
Ok, I found the solution: git submodule sync instead of git submodule deinit.
Indeed, git submodule sync
will copy the submodule URL from .gitmodules
to submodule.modulpath.url
in .git/config
and then to remote.origin.url
in .git/modules/modulpath/config
.
But I still wonder where git has stored the old submodule url and why the submodule origin was pointing there even though .git/config had the correct url for origin.
It was stored in the config file of the submodule repository, as mentioned above. remote.origin.url
in the submodule config file is where the URL used to communicate with the submodule remote is taken from.
Why did git submodule deinit not reset the submodule url regardless the fact that git submodule sync does the job more conveniently without deleting the whole submodule folder?
git submodule deinit
does nothing more than removing the submodule
section(s) from the .git/config
of the superproject, as documented in 1.
Where was the old submodule url stored? Why had this "secret" store precedence over .git/config?
As mentioned above, the URL is stored in the config file of the submodule repository. It is not "secret", a submodule is just a regular Git repository inside another Git repository, it makes sense that the same configuration used to configure a remote URL (remote.origin.url
) is also used in submodules.
Is it a bug in git that git submodule deinit -f --all does not delete the upload pack of the submodule?
"delete the upload pack of the submodule" does not make much sense, upload-pack is a Git command invoked by git fetch
. It is not a bug that git submodule deinit
does not touch the config file of the submodule, it just touches the config file of the superproject.