325

我有一个带有指向无效提交的子模块的项目:子模块提交仍然是本地的,当我尝试从另一个仓库中获取它时,我得到:

$ git submodule update
fatal: reference is not a tree: 2d7cfbd09fc96c04c4c41148d44ed7778add6b43
Unable to checkout '2d7cfbd09fc96c04c4c41148d44ed7778add6b43' in submodule path 'mysubmodule'

我知道子模块 HEAD 应该是什么,有什么方法可以在本地更改它,而无需从确实有 commit的 repo 推送2d7cfbd09fc96c04c4c41148d44ed7778add6b43

我不确定我是否清楚......这是我发现的类似情况。

4

13 回答 13

391

假设子模块的存储库确实包含您要使用的提交(与从超级项目的当前状态引用的提交不同),有两种方法可以做到这一点。

第一个要求您已经知道要使用的子模块的提交。它通过直接调整子模块然后更新超级项目来“从内到外”工作。第二个从“外部,内部”工作,通过查找修改子模块的超级项目提交,然后重置超级项目的索引以引用不同的子模块提交。

反了

如果您已经知道要让子模块使用哪个提交,请到cd子模块,检查您想要的提交,然后git addgit commit其返回到超级项目中。

例子:

$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'

糟糕,有人做了一个超级项目提交,它引用了子模块中未发布的提交sub。不知何故,我们已经知道我们希望子模块处于 commit 状态5d5a3ee314476701a20f2c6ec4a53f88d651df6c。去那里直接检查一下。

在子模块中结帐

$ cd sub
$ git checkout 5d5a3ee314476701a20f2c6ec4a53f88d651df6c
Note: moving to '5d5a3ee314476701a20f2c6ec4a53f88d651df6c' which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
  git checkout -b <new_branch_name>
HEAD is now at 5d5a3ee... quux
$ cd ..

由于我们正在检查一个提交,这会在子模块中产生一个分离的 HEAD。如果您想确保子模块正在使用一个分支,请使用git checkout -b newbranch <commit>在提交时创建和签出一个分支或签出您想要的分支(例如,在提示处带有所需提交的分支)。

更新超级项目

子模块中的签出在超级项目中反映为对工作树的更改。所以我们需要在超级项目的索引中对变化进行分阶段并验证结果。

$ git add sub

检查结果

$ git submodule update
$ git diff
$ git diff --cached
diff --git c/sub i/sub
index e47c0a1..5d5a3ee 160000
--- c/sub
+++ i/sub
@@ -1 +1 @@
-Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

子模块更新是静默的,因为子模块已经在指定的提交处。第一个差异表明索引和工作树是相同的。第三个差异表明唯一的分阶段更改是将sub子模块移动到不同的提交。

犯罪

git commit

这将提交固定的子模块条目。


外,内

如果您不确定应该从子模块中使用哪个提交,您可以查看超级项目中的历史来指导您。您还可以直接从超级项目管理重置。

$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'

这与上述情况相同。但这一次我们将专注于从超级项目中修复它,而不是将其浸入子模块中。

查找超级项目的错误提交

$ git log --oneline -p -- sub
ce5d37c local change in sub
diff --git a/sub b/sub
index 5d5a3ee..e47c0a1 160000
--- a/sub
+++ b/sub
@@ -1 +1 @@
-Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c
+Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
bca4663 added sub
diff --git a/sub b/sub
new file mode 160000
index 0000000..5d5a3ee
--- /dev/null
+++ b/sub
@@ -0,0 +1 @@
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

好的,看起来它在 中坏了ce5d37c,所以我们将从其父模块 ( ce5d37c~) 中恢复子模块。

或者,您可以从补丁文本 ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) 中获取子模块的提交,并改用上述“由内而外”的过程。

在超级项目中结帐

$ git checkout ce5d37c~ -- sub

这会将子模块条目重置为在超级项目sub中提交时的内容。ce5d37c~

更新子模块

$ git submodule update
Submodule path 'sub': checked out '5d5a3ee314476701a20f2c6ec4a53f88d651df6c'

子模块更新正常(它表示 HEAD 已分离)。

检查结果

$ git diff ce5d37c~ -- sub
$ git diff
$ git diff --cached
diff --git c/sub i/sub
index e47c0a1..5d5a3ee 160000
--- c/sub
+++ i/sub
@@ -1 +1 @@
-Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

第一个差异显示sub现在在ce5d37c~. 第二个差异表明索引和工作树是相同的。第三个差异显示唯一的分阶段更改是将sub子模块移动到不同的提交。

犯罪

git commit

这将提交固定的子模块条目。

于 2010-01-29T10:53:49.490 回答
192

试试这个:

git submodule sync
git submodule update
于 2010-10-17T13:50:10.387 回答
17

此错误可能意味着子模块中缺少提交。也就是说,存储库 (A) 有一个子模块 (B)。A 想要加载 B 以便它指向某个提交(在 B 中)。如果该提交以某种方式丢失,您将收到该错误。一次可能的原因:对提交的引用是在 A 中推送的,但实际提交不是从 B 推送的。所以我从那里开始。

不太可能,存在权限问题,并且无法拉取提交(如果您使用的是 git+ssh 则可能)。

确保 .git/config 和 .gitmodules 中的子模块路径看起来没问题。

最后一件事要尝试 - 在子模块目录中: git reset HEAD --hard

于 2011-11-15T21:25:13.260 回答
10

可能的原因

这可能发生在以下情况:

  1. 子模块已就地编辑
  2. 提交的子模块,它更新指向的子模块的哈希值
  3. 未推送子模块。

例如发生了这样的事情:

$ cd submodule
$ emacs my_source_file  # edit some file(s)
$ git commit -am "Making some changes but will forget to push!"

此时应该推送子模块。

$ cd .. # back to parent repository
$ git commit -am "updates to parent repository"
$ git push origin master

结果,远程用户不可能找到丢失的提交,因为它们仍在本地磁盘上。

解决方案

通知修改子模块的人推送,即

$ cd submodule
$ git push
于 2014-09-04T10:21:26.807 回答
8

您的分支可能不是最新的,这是一个简单的解决方案,但请尝试git fetch

于 2019-06-27T15:25:43.580 回答
7

当我这样做时,我得到了这个错误:

$ git submodule update --init --depth 1

但父项目中的提交指向更早的提交。

删除子模块文件夹并运行:

$ git submodule update --init

没有解决问题。我删除了 repo 并在没有深度标志的情况下再次尝试,它起作用了。

此错误发生在 Ubuntu 16.04 git 2.7.4 中,但不在 Ubuntu 18.04 git 2.17 中。

@pavan kumar 在评论中指出:

我只是增加了深度计数以包括旧提交并且它起作用了。

于 2014-09-16T17:43:41.297 回答
5

当您有一个子模块指向已重新定位的存储库并且给定的提交已“消失”时,这也可能发生。虽然提交可能仍在远程存储库中,但它不在分支中。如果您无法创建新分支(例如,不是您的存储库),您将不得不更新超级项目以指向新的提交。或者,您可以将您的子模块副本之一推送到其他地方,然后更新超级项目以指向该存储库。

于 2012-01-29T09:19:20.483 回答
2

此答案适用于终端 git 经验有限的 SourceTree 用户。

从 Git 项目(超级项目)中打开有问题的子模块。

获取并确保选中“获取所有标签”。

Rebase 拉取你的 Git 项目。

这将解决十次中有九次“参考不是树”的问题。1 次它不会,是一个终端修复,如最佳答案所述。

于 2016-10-26T23:40:54.363 回答
1

无论如何,您的子模块历史记录都安全地保存在子模块 git 中。

那么,为什么不直接删除子模块并重新添加呢?

HEAD否则,您是否尝试refs/master/head在子模块中手动编辑.git

于 2010-01-29T07:22:28.393 回答
1

可以肯定的是,请尝试更新您的git二进制文件。

GitHub for Windows 的版本git version 1.8.4.msysgit.0在我的情况下是问题所在。更新解决了。

于 2014-02-13T17:27:16.603 回答
1

就我而言,即使它们是很好的答案,上述答案都不能解决问题。所以我发布了我的解决方案(在我的情况下,有两个 git 客户端,客户端 A 和 B):

  1. 转到子模块的目录:

    cd sub
    
  2. 结帐到大师:

    git checkout master
    
  3. 重新设置为两个客户端都可以看到的提交代码

  4. 回到父目录:

  5. 致力于掌握

  6. 换另一个客户端,再做rebase一次。

  7. 现在终于可以正常使用了!也许会丢失几个提交,但它有效。

  8. 仅供参考,不要尝试删除您的子模块,它将保留.git/modules在那里并且无法再次读取此子模块,除非是本地响应式模块。

于 2015-10-20T05:15:26.897 回答
1

要将 git repo 与子模块的头部同步,如果这确实是您想要的,我发现删除子模块然后读取它可以避免修改历史记录。不幸的是,删除子模块需要破解而不是单个 git 命令,但可行。

受https://gist.github.com/kyleturner/1563153启发,我删除子模块的步骤如下:

  1. 运行 git rm --cached
  2. 从 .gitmodules 文件中删除相关行。
  3. 从 .git/config 中删除相关部分。
  4. 删除现在未跟踪的子模块文件。
  5. 删除目录 .git/modules/

同样,如果您只想再次指向子模块的头部,并且您不需要保持子模块的本地副本完整无缺,这将很有用。它假定您将子模块“正确”作为自己的存储库,无论它的来源在哪里,并且您只想重新正确地将其包含为子模块。

注意:在进行此类操作或任何 git 命令之前,请始终制作项目的完整副本,而不是简单的提交或推送。我也建议所有其他答案,并作为一般的 git 指南。

于 2015-10-29T11:48:11.617 回答
1

只是偶然发现了这个问题,这些解决方案都不适合我。结果证明我的问题的解决方案实际上要简单得多:升级 Git。我的是1.7.1,升级到2.16.1(最新)后,问题消失得无影无踪!猜猜我把它留在这里,希望它可以帮助某人。

于 2018-02-04T12:17:26.733 回答