【问题标题】:how to undelete a folder that was a submodule removed via git rm如何取消删除作为通过 git rm 删除的子模块的文件夹
【发布时间】:2021-10-14 11:04:35
【问题描述】:

我需要取消删除显示为子模块的文件夹的未提交的 git rm。

这比你想象的要复杂。

在我在 GitHub 上的私人仓库中,我找到了一个子模块。这是出乎意料的。 GitHub 项目页面将子模块显示为带有箭头的文件夹,但无法点击。

本地有一个子模块名称的文件夹,其中有一个 .git 文件夹。表示本地一直是git init

我在本地重命名了子模块文件夹中的 .git 文件夹并从父级运行 git rm -f folder

认为它会摆脱子模块,只留下真正的文件夹,然后我可以 git add 回到 repo

但它在本地删除了该文件夹,现在以下命令似乎都无法取回它。 请记住,作为子模块列出的文件夹从未提交到 git 服务器。但是它所在的文件夹有。

尝试了以下所有方法

git reset HEAD folder
git add folder
git checkout -- folder
git reset HEAD folder/*

并将 git 更新到 2.33.1 也可以尝试

git restore folder
git restore folder/*

git status

目前显示

On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    folder

.git/config 没有引用子模块

我在这个帖子中读到的任何内容都没有帮助 Restore a deleted folder in a Git repo

【问题讨论】:

  • git restore --staged folder 也什么都不做,没有错误
  • 试试git submodule update folder
  • 我在本地重命名了子模块文件夹中的 .git 文件夹并从父级 git rm -f 文件夹运行 ...好的,但是 你把原来的.git文件夹?
  • 我将它从 .git 重命名为 .git_old 希望父 git repo 会看到不再有任何关于“文件夹”的 gity,但是当我尝试 git 时它没有意识到这些变化添加-A
  • 啊 - 唉,这设置了 git rm -f 可能愿意删除它。 (我自己没有测试过。)

标签: git git-submodules


【解决方案1】:

在我在 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。然后,对于每个超级项目和/或子模块提交,我将进行另一个新提交以更新新组合项目中的所有文件。但这只是一个演示。

【讨论】:

  • 哇。谢谢你,我学到了很多。我不得不恢复备份。
猜你喜欢
  • 1970-01-01
  • 2017-05-29
  • 1970-01-01
  • 2023-03-09
  • 2013-03-31
  • 1970-01-01
  • 2019-08-14
  • 1970-01-01
  • 2017-12-16
相关资源
最近更新 更多