Gitサブモジュールヘッドの「参照はツリーではありません」エラー


305

無効なコミットを指しているサブモジュールを持つプロジェクトがあります。サブモジュールのコミットはローカルのままで、別のリポジトリからフェッチしようとすると、次のようになります。

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

私はサブモジュールHEADがどうあるべきかを知ってます、コミットているリポジトリからプッシュせずにこれをローカルで変更する方法はあります2d7cfbd09fc96c04c4c41148d44ed7778add6b43か?

私が明確であるかどうかはわかりません...これは私が見つけた同様の状況です。


11
サブモジュールに関する「致命的:参照はツリーではありません」は、一般的に、親リポジトリがまだプッシュされていない、または他の方法でねじ込まれていると期待するサブモジュールのコミットを意味するようです。私たちにとって、この紛らわしいエラーメッセージは、誰かがプッシュするのを忘れたサブモジュールをプッシュすることで解決されました。
Chris Moschini 2014年

1
@ChrisMoschini-私はちょうどその問題があり、それが私の「解決策」でした。メインリポジトリをプッシュしてプルしましたが、最後のコミットをサブモジュールのリポジトリにプッシュするのを忘れていました。ありがとう!
Rotem 2016年

たぶん、最新のサブモジュールコミットをプッシュするのを忘れていました
Hafenkranich

回答:


378

サブモジュールのリポジトリに使用したいコミットが含まれていると(スーパープロジェクトの現在の状態から参照されるコミットとは異なり)、それを行うには2つの方法があります。

1つ目は、使用するサブモジュールからのコミットをすでに知っている必要があります。サブモジュールを直接調整してスーパープロジェクトを更新することにより、「内部、外部」から機能します。2番目は、サブモジュールを変更したスーパープロジェクトのコミットを見つけ、別のサブモジュールコミットを参照するようにスーパープロジェクトのインデックスをリセットすることにより、「外部から」の作業を行います。

内側、外側

あなたはすでにあなたが使用するサブモジュールを表示したいコミットわかっている場合、cdサブモジュールに、必要なコミットをチェックアウトし、git addそしてgit 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

サブモジュールはすでに指定されたコミットにあるため、サブモジュールの更新はサイレントでした。最初のdiffは、インデックスとワークツリーが同じであることを示しています。3番目の差分は、段階的な変更が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

OK、問題が発生したようです。ce5d37cサブモジュールを親(ce5d37c~)から復元します。

あるいは、パッチテキスト(5d5a3ee314476701a20f2c6ec4a53f88d651df6c)からサブモジュールのコミットを取得し、代わりに上記の「内部、外部」プロセスを使用できます。

スーパープロジェクトでのチェックアウト

$ git checkout ce5d37c~ -- sub

これにより、サブプロジェクトのエントリが、スーパープロジェクトのsubコミット時の状態にリセットされましたce5d37c~

サブモジュールを更新する

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

サブモジュールの更新はOKになりました(ヘッドが切り離されていることを示しています)。

結果を確認する

$ 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~ます。2番目のdiffは、インデックスとワークツリーが同じであることを示しています。3番目の差分は、段階的な変更がsubサブモジュールを別のコミットに移動することだけであることを示しています。

コミット

git commit

これにより、修正されたサブモジュールエントリがコミットされます。


「Outside、In」アプローチで、「ce5d37cで問題が発生したように見える」理由を説明できますか?何が悪いコミットだと思っているのですか?
Garrett Albright

5
@Garrett:前提はe47c0a、のローカルリポジトリに存在しないコミットですがsub、スーパープロジェクトsubはそのコミットをポイントしています。これは、他の誰かe47c0aがのコピーで作成し、subそのコミットを指すようにスーパープロジェクトを更新e47c0aし、の中央/共有リポジトリにプッシュせずにスーパープロジェクトをプッシュしたために発生した可能性がありますsub。我々は、中央/共有超のプロジェクトから引くと、私たちはそのポイントをコミット取得sube47c0aコミットしているが、我々は「見る」ことができません。ce5d37c差分に基づいて導入されたため、疑わしいe47c0aです。
Chris Johnsen、2011

subサブモジュールとしてそれを持っている親リポジトリに保持されている特定のハッシュがどこにあるか、そしてsub親の古い状態に依存することなく直接現在のHEADに直接操作できるかどうかはまだ曖昧なままです常に役立つとは限りません。
matanster


187

これを試して:

git submodule sync
git submodule update

2
残念ながら私にはありませんが、サブモジュールの1つがメインのgitリポジトリのターゲットに追加コマンドを使用していたため、元に戻すことができませんでした
Daniel

9
私も働いた。なぜか知りたいです。
BenBtg

12
git submodule sync特定のサブモジュールのリモートのURLが変更されたシナリオでは、aを実行する必要があることがわかります。私たちのケースでは、パブリックレポからサブモジュールを追加してから、URLをプライベートフォークに変更し、この特定のピクルに取りかかりました。
Samscam

たとえば、githubリポジトリ(B)を指すサブモジュールを使用してリポジトリ(A)をセットアップしました。他の誰かのgithubリポジトリをBに向けたいので、リポジトリAにブランチを作成しました。少し苦労してブランチをコミットした後、リポジトリAをマスターに戻し、リポジトリBでこの問題が発生しました。@ Lonre Wangのソリューションで修正しました。
fbicknel 2014年

2
だれも本当に台無しにしないと仮定すると(この場合はChris Johnsenの優れた答えが必要です)、Lonre Wangの答えで問題が解決するはずです...サブモジュールに独自のサブモジュールがない限り(問題はサブモジュール内にあります)。その場合は、問題のあるサブモジュールがあるサブモジュールにcdして、上記のコマンドを実行する必要があります。updateには--recursiveオプション(git submodule update --recursive)がありますが、同期にはありません。問題のあるサブ(サブ)モジュールがあるサブモジュール内で「git submodule sync」を手動で実行する必要があります。これが私の問題でした;)
Carlo Wood

16

このエラーは、サブモジュールでコミットが欠落していることを意味する場合があります。つまり、リポジトリ(A)にはサブモジュール(B)があります。Aは、(B内の)特定のコミットを指すようにBをロードしようとしています。そのコミットが何らかの形で欠落している場合は、そのエラーが発生します。考えられる原因:コミットへの参照がAにプッシュされましたが、実際のコミットはBからプッシュされませんでした。

可能性は低いですが、権限の問題があり、コミットをプルできません(git + sshを使用している場合は可能です)。

サブモジュールのパスが.git / configと.gitmodulesで問題ないことを確認してください。

最後に試すこと-サブモジュールディレクトリ内:git reset HEAD --hard


3
私はすでに質問でそれを説明しました...問題自体はそれをどのように解決するかでした。そして、それはほぼ2年前にすでに成功裏に回答されています...許可はこれとは何の関係もありません。
Mauricio Scheffer

1
あなたはそれを述べました、あなたは確かにそれを説明しませんでした。
ダニエル・ツァドク

私の要点は、この回答は価値のある情報を追加しないため、削除することです。
Mauricio Scheffer

4
「git reset HEAD --hard」も私を助けてくれました...他には何もうまくいきませんでした。私も以前の解決策を試しました、サイコロはありません。ありがとう!
ヴァージル

1
各スレッドはオンラインの小さな世界です。あなたが言うことはあなたを表します-あなたがあなたが望む敬意をあなたに与えるコンテキストであなたのコメントを組み立てようとするために人々があなたの個人的な歴史を研究することを期待することはできません。親切に、敬意を払ってください。そうすれば、自分の癖について人々に理解してもらう必要はありません。中立的な文脈からコメントを読むことができれば、部外者のように、私の批判を理解するでしょう。
Stabledog 2013

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

6

私がしたときにこのエラーが発生しました:

$ git submodule update --init --depth 1

しかし、親プロジェクトのコミットは以前のコミットを指していた。

サブモジュールフォルダーを削除して実行:

$ git submodule update --init

問題は解決しませんでした。私はリポジトリを削除し、深度フラグなしで再試行しましたが、うまくいきました。

このエラーはUbuntu 16.04 git 2.7.4では発生しますが、Ubuntu 18.04 git 2.17では発生しません。TODOは正確な修正コミットまたはバージョンを見つけます。


私のチームはそれ以来、コード内のサブモジュールを放棄しすぎています。面倒ですlol
Plato

1
あなたの代わりは何でしたか?
nuzzolilo

@nuzzoliloをusername/repo#shapackage.json に追加しました。より柔軟なオプションは、Docker コンテナーのセットでシステムを整理することです
Plato

3
これはとても迷惑です。--depth=1リポジトリの履歴が必要ないときに、帯域幅を大幅に節約できます。誰かがこれがなぜ起こっているのかを発見または知っているなら、私は知りたいです。
i336_

@ i336_理由を説明することはできませんが、github.com / LMMS / lmms / blob /…で問題の緩和に役立つcmakeヘルパーを作成しましたdeinitほとんどの場合、問題を解決するアプローチを使用します。ビルドシステムにバンドルされている場合、エンドユーザーはビルドシステムにサブモジュールをフェッチさせ、壊れたrecursiveコマンドを完全に破棄できます。サブモジュールが強制プッシュを実行し、コミットを完全に消去するなど、これが壊れるシナリオはまだあります。
tresf 2018年

5

これは、リベースされたリポジトリを指すサブモジュールがあり、指定されたコミットが「なくなった」場合にも発生する可能性があります。コミットはまだリモートリポジトリにある可能性がありますが、ブランチにはありません。新しいブランチ(たとえば、リポジトリではない)を作成できない場合、スーパープロジェクトを更新して新しいコミットをポイントする必要があります。または、サブモジュールのコピーの1つを他の場所にプッシュし、スーパープロジェクトを更新して、代わりにそのリポジトリを指すようにすることもできます。



2

この回答は、ターミナルgitの経験が限られているSourceTreeのユーザーを対象としています。

Gitプロジェクト(スーパープロジェクト)から問題のあるサブモジュールを開きます。

[すべてのタグを取得する]が取得されていることを確認します。

Gitプロジェクトをリベースプルします。

これにより、「参照はツリーではない」問題が10回のうち9回解決されます。最初の回答で説明されているように、1回はそうではありません。


1

とにかく、サブモジュールの履歴はサブモジュールgitに安全に保存されます。

それでは、なぜサブモジュールを削除して再度追加しないのですか?

それ以外の場合、サブモジュール内でHEADまたはを手動で編集してみましたかrefs/master/head.git


1
これは機能しません。どこかに2d7cfbd09fc96c04c4c41148d44ed7778add6b43への参照があるためです。これは、他の場所のローカルリポジトリにのみ存在しますが、公開されていません
Mauricio Scheffer

1

念のため、gitバイナリを更新してみてください。

GitHub for Windowsには、git version 1.8.4.msysgit.0私の場合問題だったバージョンがあります。更新することで解決しました。


1

私の場合、上記の答えはどれも問題を解決できません。だから私は私の解決策を投稿します(私の場合、2つのgitクライアント、クライアントAとBがあります):

  1. サブモジュールのディレクトリに移動します:

    cd sub
    
  2. マスターするチェックアウト:

    git checkout master
    
  3. 両方のクライアントが見ることができるコミットコードにリベース

  4. 親のディレクトリに戻ります:

  5. マスターする

  6. 他のクライアントに変更し、rebase再度実行してください。

  7. やっとうまくいきました!いくつかのコミットを失うかもしれませんが、それは機能します。

  8. .git/modulesちなみに、サブモジュールを削除しようとしないでください。サブモジュールはそのまま残り、ローカルのサブモジュールがアクティブでない限り、このサブモジュールを再度読み取ることはできません。


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ガイドラインとしてそれをお勧めします。


1

この問題に遭遇しただけで、これらの解決策はどれも私にとってうまくいきませんでした。私の問題の解決策であることが判明したのは、実際にははるかに簡単です。Gitをアップグレードします。私は1.7.1でしたが、2.16.1(最新)にアップグレードした後、問題は跡形もなく消えました!私がそれをここに残していると思います、それが誰かを助けることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.