Git子模块头'引用不是树'的错误

我有一个子模块项目指向一个无效的提交:子模块提交保持本地,当我试图从另一个回购获取它:

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

我知道子模块HEAD应该是什么,有没有什么办法可以在本地进行更改,而无需从提交2d7cfbd09fc96c04c4c41148d44ed7778add6b43的回购中2d7cfbd09fc96c04c4c41148d44ed7778add6b43

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

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

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

反了

如果你已经知道你希望子模块使用哪个提交,请cd到子模块,检查你想要的提交,然后git addgit commitgit commit回超级项目。

例:

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

糟糕的是,有人做了一个超级项目提交,提交了子模块sub中的一个未发布的提交。 不知何故,我们已经知道我们希望子模块在提交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 checkout -b newbranch <commit>时创build并签出一个分支,或者检出你想要的分支(例如,在提示中需要提交的分支) )。

更新超级项目

子模块中的签出会在超级项目中反映为对工作树的更改。 因此,我们需要在超级项目的索引中进行变更并validation结果。

 $ 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 

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


外面,在

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

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

这与上面的情况是一样的。 但是这次我们将把重点放在从超级项目中解决,而不是陷入子模块。

find超级项目的恶意提交

 $ 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 

第一个差异显示,现在subce5d37c~是相同的。 第二个差异表明索引和工作树是一样的。 第三个差异显示了唯一的阶段性变化是将sub子模块移动到另一个提交。

承诺

 git commit 

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

尝试这个:

 git submodule sync git submodule update 

这个错误可能意味着子模块中缺less一个提交。 也就是说,存储库(A)有一个子模块(B)。 A想要加载B,以便它指向某个提交(在B中)。 如果这个提交失败了,你会得到这个错误。 一旦可能的原因:对提交的引用被推入A,但实际的提交不是从B推。所以我会开始在那里。

不太可能,有一个权限问题,提交不能被拉(可能,如果你使用git + ssh)。

确保.git / config和.gitmodules中的子模块path正常。

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

可能的原因

这可能发生在:

  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 

我遇到这个错误时:

 $ git submodule update --init --depth 1 

但是父项目中的提交指向了更早的提交。
删除子模块文件夹并运行

 $ git submodule update --init 

没有解决问题。 我删除了回购,并没有深度标志再次尝试,它的工作。

当您有一个子模块指向一个已重新绑定的存储库并且给定的提交“已离开”时,也可能发生这种情况。 虽然提交可能仍在远程存储库中,但它不在分支中。 如果你不能创build一个新的分支(例如不是你的仓库),那你就不得不更新超级项目来指向一个新的提交。 或者,您可以将其中一个子模块的其中一个副本推送到其他位置,然后将超级项目更新为指向该存储库。

这个答案是用于SourceTree的用户与有限的terminal混帐经验。

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

获取并确保检查“取所有标签”。

重新拉你的Git项目。

这将解决“参考不是一棵树”的十个问题。 这一次它不会,是最好的答案描述的terminal修复。

无论如何,你的子模块历史logging都保存在submodule git中。

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

否则,您是否尝试手动编辑子模块.gitHEADrefs/master/head

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

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

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

  1. 去子模块的目录:

     cd sub 
  2. 结账掌握:

     git checkout master 
  3. 重新绑定到客户端可以看到的提交代码

  4. 回到父母的目录:

  5. 承诺掌握

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

  7. 终于现在工作正常! 也许失去了几个提交,但它的作品。

  8. 仅供参考,不要尝试删除你的子模块,它将保持.git/modules在那里,不能再读这个子模块,除非被动的本地模块。

要将git repo与子模块的头同步,万一你真的想要,我发现删除子模块然后读取它避免了修改历史。 不幸的是,删除一个子模块需要黑客,而不是一个单一的git命令,但可行。

我通过https://gist.github.com/kyleturner/1563153启发删除子模块的步骤&#xFF1A;

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

同样,如果您只需要再次指向子模块的头部,并且您不需要保持子模块的本地副本完好无损,就可以实现这一点。 它假设你有子模块“正确”作为自己的回购,无论它的起源在哪里,你只是想回到正确的包括它作为一个子模块。

注意:除了简单的提交或推送之外,在进行这些types的操作或任何git命令之前,请始终完整地复制项目。 我build议,所有其他的答案,以及作为一个总的git指导方针。