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
即使子模块仓库地址在branch001和branch002之间发生了变化,一切都很好。 我可以预期这会起作用,因为
.git/config
已通过将branch002克隆到中而被删除
一个空目录。但是,或者,我也可以使用 .git/config
命令删除 git submodule deinit
中的子模块条目,如下所示(它可以执行更多操作,但我认为这与此处无关):
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
但令人惊讶的是最后一个命令仍然失败了:
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.
看起来 old_submodule_repo 仍然存储在某个地方。所以我检查一下:
$ 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
好吧,我找到了解决方案:
git submodule sync
而不是git submodule deinit
。
但我仍然想知道 git 在哪里存储了旧的子模块 url,以及为什么子模块 origin 指向那里,即使
.git/config
具有正确的 origin url。
当我说
git set-url origin ...
时,我希望这能反映在 .git/config
文件中并得到尊重。如果我直接对 .git/config
文件进行更改,我也希望得到尊重。在这两种情况下,它都受到尊重。但对于子模块,事情似乎不一样了。
所以我的问题是:
git submodule deinit
没有重置子模块 url,尽管 git submodule sync
在不删除整个子模块文件夹的情况下可以更方便地完成工作?.git/config
?git submodule deinit -f --all
不删除子模块的上传包是git的bug吗?看起来 old_submodule_repo 仍然存储在某个地方。所以我做 一张支票:
$ 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
第二个命令应该找到
./.git/modules/modulpath/config
,因为这是子模块远程的 remote.origin.url
配置的最终存储位置。我不知道为什么你的调用找不到它(它对我有用)。也许您有非标准设置?
好吧,我找到了解决方案:git submodule sync 而不是 git submodule deinit。
确实,
git submodule sync
会将子模块 URL 从 .gitmodules
复制到 submodule.modulpath.url
中的 .git/config
,然后复制到 remote.origin.url
中的 .git/modules/modulpath/config
。
但我仍然想知道 git 在哪里存储了旧的子模块 url,以及为什么子模块 origin 指向那里,即使 .git/config 具有正确的 origin url。
它存储在子模块存储库的配置文件中,如上所述。子模块配置文件中的
remote.origin.url
是用于与子模块远程通信的URL的来源。
为什么 git submodule deinit 没有重置子模块 url,尽管 git submodule sync 可以更方便地完成这项工作,而无需删除整个子模块文件夹?
git submodule deinit
只是从超级项目的 sumodule
中删除 .git/config
部分,如 1 中所述。
旧的子模块 url 存储在哪里? 为什么这个“秘密”存储优先于 .git/config?
如上所述,URL 存储在子模块存储库的配置文件中。这不是“秘密”,子模块只是另一个 Git 存储库中的常规 Git 存储库,用于配置远程 URL (
remote.origin.url
) 的相同配置也用于子模块中是有意义的。
git submodule deinit -f --all 没有删除子模块的上传包,是不是git的bug?
“删除子模块的上传包”没有多大意义,upload-pack是
git fetch
调用的Git命令。 git submodule deinit
没有触及子模块的配置文件,这不是一个错误,它只是触及了超级项目的配置文件。