Git 在添加之前还原主存储库后没有删除子模块

Git didn't remove submodule after reverting main repository before it was added

事情是这样发生的:

  1. 我检查了一个添加了新子模块的分支。
  2. 然后,当子模块未添加时,我返回到另一个分支上的提交。
  3. 现在我无法编译,因为签出的子模块还在磁盘上;文件存在,如果我转到终端上的根目录,它仍然存在。

那么我该如何解决这个问题呢?当我返回到它从未存在过的提交时,为什么 git 没有删除该文件夹。

我试过:

没有任何东西可以删除它。我不想手动删除它,因为那不是 git 方式。

So how do I fix this?

从您的工作树中手动删除所有子模块文件:例如 rm -rf submodule

Why didn't git delete the folder when I went back to a commit where it never existed.

子模块很乱。

请记住,Git 中的子模块实际上只是另一个 Git 存储库。这个另一个 Git 存储库完全独立于您的主(超级项目)存储库。或者更确切地说,它会是——你只有两个单独的克隆,并排在一起,它们之间根本没有交互——除了你已经将子模块克隆插入到 [=48 的工作树中的事实之外=]超级项目。并且,在这个过程中:

  • 在现代 Git 中,存储库本身会 "absorbed" 进入超级项目的存储库目录(因此没有 .git 文件夹 而是 .git file 在子模块签出提交的工作树副本中。

  • 超级项目的Git记录了超级项目配置(不仅仅是.gitmodule文件)和一些关于子模块的内容提交。特别是,在子模块应该在某个特定哈希 ID 处检出的提交中,哈希 ID 本身存储为每个提交中的 gitlink 条目。

  • 超级项目的 Git 保持 cd-ing 进入子模块并执行 git checkout <hash-id> 分离子模块中的 HEAD。 (确切地 何时 这样做是另一个问题;这取决于您是否启用了子模块递归。)

一般来说,子模块是一个(大部分)独立的存储库这一事实阻止了超级项目 Git 完全删除它。在这种特殊情况下,它可能 应该 继续并将其作为 "update the submodule to the correct commit" 的一部分删除,因为相关子模块中的 "correct" 提交是 "no commit at all - remove the submodule from the work-tree".在过去,在 Git 将 .git 目录吸收到超级项目之前,这实际上会破坏子模块存储库,这很糟糕。1 在现代 Git,它不会(至少吸收了子模块.git目录),所以它可以工作。


1在很多情况下,如果没有重新克隆的需要,它是无害的。但是假设您通过以下方式提交了一个超级项目:(1)在您创建的 in 子模块的新分支上提交子模块; (2) 退出子模块回到父项目,更新index gitlink entry,记录子模块中新的hash ID; (3) 进行新的提交。您现在有一个未推送到任何地方的子模块提交,但可以而且应该在推送超级项目提交之前推送。

现在您已完成所有设置,您决定查看历史提交。您 git checkout <hash> 在超级项目中,并且该历史提交 没有 检出子模块。您已将 submodule.recurse 设置为 true 或已使用 git checkout --recurse-submodules 以便超级项目将子模块带到正确的(缺少)提交,并且 删除子模块.

由于 .git 目录确实存在 子模块中——在子模块的工作树中——这完全地、不可撤销地破坏了你在子模块中所做的提交,在你在那里做的分支,你还没有推动。所以这个一定不能做。

现在 .git 目录本身位于其他地方,从超级项目的工作树中物理删除子模块不会损害子模块 repository。所以现在,这种移除是安全的。将超级项目恢复到最新的提交可以简单地恢复子模块的工作树,检查受子模块存储库分支(仍未推送)GC 保护的提交。