1. ホーム
  2. git

[解決済み】Git サブモジュール head 'reference is not a tree' エラー

2022-02-02 12:50:18

質問内容

私は無効なコミットを指しているサブモジュールを持つプロジェクトを持っています:サブモジュールのコミットはローカルのままで、私は他のリポジトリからそれをフェッチしようとすると、私は取得します。

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

サブモジュールの HEAD がどうあるべきかはわかっていますが、これをローカルに変更する方法はないでしょうか。 が行います。 コミット 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 ?

よくわからないのですが・・・。 同じような状況はこちら 発見しました。

解決方法は?

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

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

インサイド、アウト

サブモジュールが使用するコミットが既に決まっている場合。 cd をサブモジュールに追加し、必要なコミットをチェックアウトし、次に git addgit 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 ..

コミットをチェックアウトしているので、サブモジュールの中では detached 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 番目の diff では、段階的な変更といえば 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 ) の代わりに、上記の「inside, out」処理を使用します。

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

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

コミット

git commit

これは、修正されたサブモジュールのエントリをコミットします。