在我在 GitHub 上的私人仓库中,我找到了一个子模块。这是出乎意料的。 GitHub 项目页面将子模块显示为带有箭头的文件夹,但无法点击。
这表明子模块......充其量是不完整的,最坏的情况是完全损坏。
本地有一个子模块名称的文件夹,其中有一个.git 文件夹。表示本地一直是git init。
可能——或者你或某人运行git clone 来创建它。无论哪种方式,.git 目录(文件夹)都包含实际的 repository。
如果该特定存储库有其他克隆,则这些其他克隆存在,并且具有它们所具有的任何最新状态。如果不存在,则它们不存在。
我在本地重命名了子模块文件夹中的.git文件夹并从父git rm -f folder运行
这一切都很好,除了一个重要的信息。您已重命名(或移动)此 .git。 你把它放在哪里了?
让我们建立一个类似的情况。请注意 Git 在此处打印的长警告和 hint 序列:
$ cd ~/tmp
$ mkdir tt
$ cd tt
$ git init
Initialized empty Git repository in .../tt/.git
$ mkdir sub
$ cd sub
$ git init
Initialized empty Git repository in .../tt/sub/.git
$ echo for testing > README
$ git add README
$ git commit -m initial
[master (root-commit) 1fd3599] initial
1 file changed, 1 insertion(+)
create mode 100644 README
$ cd ..
$ git add sub
warning: adding embedded git repository: sub
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint:
hint: git submodule add <url> sub
hint:
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint:
hint: git rm --cached sub
hint:
hint: See "git help submodule" for more information.
这样做是用 gitlink 准备我的下一次提交。
gitlink 是子模块中最重要的部分。另一半,也是最重要的,? 是进入 .gitmodules 文件的内容:这是告诉 超级项目 Git(在 tt/ 中)如何克隆子模块 tt/sub.
由于我以半途而废的方式制作了这个子模块,所以我只有半个子模块:gitlink 的一半。这就是 GitHub 上不可点击的文件夹图标所代表的含义:一个 gitlink,其中子模块克隆说明要么完全丢失,要么不在 GitHub 上。 (如果子模块存储库位于其他一些公共访问站点上,也许他们会显示更多或允许点击,但如果它是完全私有的或丢失,他们不能显示更多;您可以检查确切的查看超级项目中的.gitmodules 文件。)
现在让我将我的第一个提交 in 作为我的超级项目(在tt/),这样我实际上是指子模块。然后我会做你所做的:将.git文件夹移动到某处,然后运行git rm -f sub:
$ git commit -m "initial in superproject"
[master (root-commit) 20ab8f6] initial in superproject
1 file changed, 1 insertion(+)
create mode 160000 sub
$ mv sub/.git save-the-repo
$ git rm -f sub
rm 'sub'
$ ls
save-the-repo
我还没有提交,但是一旦提交,我就会有一个没有 gitlink 的新提交。没有半途而废的子模块,也没有完全符合的子模块:什么都没有,因为我从来没有将任何其他东西放入存储库。当然,旧的 commit 仍然存在,它仍然 引用 子模块:
git commit -m 'remove half-assed submodule'
[master b01e217] remove half-assed submodule
1 file changed, 1 deletion(-)
delete mode 160000 sub
注意mode 160000,顺便说一句:这就是Git用来将某物指定为gitlink的东西。我们可以在之前的提交中看到它,而在当前的提交中它已经消失了:
$ git ls-tree -r HEAD^
160000 commit 1fd3599ca076ba9f03c88661013810a9536921ea sub
$ git diff HEAD^ HEAD
diff --git a/sub b/sub
deleted file mode 160000
index 1fd3599..0000000
--- a/sub
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 1fd3599ca076ba9f03c88661013810a9536921ea
回到你的问题
...认为它会摆脱子模块,只给我留下真正的文件夹,然后我可以 git add 回到 repo 中
我现在必须重复这个问题(已经在评论中和这里的答案中问过):您将原始 .git 文件夹放在哪里?
我把我的放在save-the-repo。我们在上面的ls 输出中看到了它。你现在的工作是腾出一个地方来存放它,并在那个地方叫它.git:
$ mkdir recover
$ mv save-the-repo recover/.git
$ cd recover
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: README
no changes added to commit (use "git add" and/or "git commit -a")
要将文件恢复到最新版本,我现在可以按照上面的建议进行操作,或者更简单地说,git restore .:
$ git restore .
$ ls
README
$ git status
On branch master
nothing to commit, working tree clean
请注意,这提取了 master 上的最新提交。这里的.git 存储库仍然存在,并且仍然包含我所做的所有提交。当然,我只提交了一次,所以这就是所有的提交。但是,如果我现在将一个 README 文件移动到sub,那是我将保存回原始存储库的唯一版本:
$ cd ..
$ ls
recover
$ mkdir sub
$ mv recover/README sub/README
$ git add sub/README
$ git commit -m "move the latest sub/* files into the main repo, losing earlier ones"
[master 2af80e1] move the latest sub/* files into the main repo, losing earlier ones
1 file changed, 1 insertion(+)
create mode 100644 sub/README
$ git log --oneline
2af80e1 (HEAD -> master) move the latest sub/* files into the main repo, losing earlier ones
b01e217 remove half-assed submodule
20ab8f6 initial in superproject
我现在有三个提交:我的第一个,我有半途而废的子模块,我的第二个,我删除了它,我的第三个,我创建 sub/ 并用文件填充它(嗯,文件, 单数)来自曾经是子模块的最新提交。超级项目的 当前 版本不依赖于任何子模块,但超级项目中的 older 提交会这样做——而且因为没有 .gitmodules 提供关于 在哪里的说明克隆子模块,那些半途而废的子模块被破坏了。
真正解决这个问题,不留下任何错误的痕迹,将涉及从头开始创建新的历史,其中子模块在开始时被正确添加,或者从一开始就从未创建为 gitlink。然后,对于每个超级项目和/或子模块提交,我将进行另一个新提交以更新新组合项目中的所有文件。但这只是一个演示。