Referensi Git submodule head bukan kesalahan pohon '

305

Saya punya proyek dengan submodule yang menunjuk ke komit yang tidak valid: komit submodul tetap lokal dan ketika saya mencoba mengambilnya dari repo lain saya mendapatkan:

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

Saya tahu apa yang harus menjadi kepala HEAD submodule, apakah ada cara saya dapat mengubah ini secara lokal, tanpa mendorong dari repo yang memang memiliki komitmen 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Saya tidak yakin apakah saya jelas ... inilah situasi serupa yang saya temukan.

Mauricio Scheffer
sumber
11
"fatal: referensi bukan pohon" dalam referensi untuk submodul umumnya berarti submodul melakukan bahwa repo induk berharap belum didorong, atau dikacaukan dengan cara lain. Bagi kami, pesan kesalahan yang membingungkan ini diselesaikan dengan hanya mendorong submodule yang seseorang lupa untuk dorong.
Chris Moschini
1
@ChrisMoschini - Saya baru saja mengalami masalah itu, dan itu adalah "solusi" saya, saya mendorong dan menarik repo utama., Tapi saya lupa untuk mendorong komit terakhir saya ke repo submodule. Terima kasih!
Rotem
Mungkin Anda lupa untuk mendorong submodule commit terbaru
Hafenkranich

Jawaban:

378

Dengan asumsi repositori submodule memang berisi komit yang ingin Anda gunakan (tidak seperti komit yang dirujuk dari keadaan super-proyek saat ini), ada dua cara untuk melakukannya.

Yang pertama mengharuskan Anda sudah tahu komit dari submodule yang ingin Anda gunakan. Ini bekerja dari "dalam, luar" dengan langsung menyesuaikan submodule kemudian memperbarui proyek-super. Yang kedua bekerja dari "luar, dalam" dengan menemukan komit proyek-super yang memodifikasi submodule dan kemudian mengatur ulang indeks proyek-super untuk merujuk ke komit submodul yang berbeda.

Luar dalam

Jika Anda sudah tahu komit mana yang Anda inginkan submodule untuk digunakan, cdke submodule, periksa komit yang Anda inginkan, lalu git adddan komit git commititu kembali di super-proyek.

Contoh:

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

Ups, seseorang membuat komit super proyek yang mengacu pada komit yang tidak dipublikasikan dalam submodule sub. Entah bagaimana, kita sudah tahu bahwa kita ingin submodule untuk dikomit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Pergi ke sana dan periksa langsung.

Checkout di Submodule

$ 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 ..

Karena kami memeriksa komit, ini menghasilkan KEPALA terpisah dalam submodule. Jika Anda ingin memastikan bahwa submodule menggunakan cabang, maka gunakan git checkout -b newbranch <commit>untuk membuat dan checkout cabang di komit atau checkout cabang yang Anda inginkan (mis. Satu dengan komit yang diinginkan di ujung).

Perbarui Super-proyek

Checkout dalam submodule tercermin dalam super-proyek sebagai perubahan pada pohon kerja. Jadi kita perlu melakukan tahapan dalam indeks proyek super dan memverifikasi hasilnya.

$ git add sub

Periksa hasilnya

$ 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

Pembaruan submodule diam karena submodule sudah di komit yang ditentukan. Perbedaan pertama menunjukkan bahwa indeks dan tabel kerja adalah sama. Perbedaan ketiga menunjukkan bahwa satu-satunya perubahan yang dipentaskan adalah memindahkan subsubmodule ke komit yang berbeda.

Melakukan

git commit

Ini melakukan entri submodul yang diperbaiki.


Di luar, Di

Jika Anda tidak yakin komit mana yang harus Anda gunakan dari submodule, Anda dapat melihat riwayat di proyek super untuk memandu Anda. Anda juga dapat mengatur reset secara langsung dari proyek-super.

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

Ini adalah situasi yang sama seperti di atas. Tapi kali ini kita akan fokus pada memperbaikinya dari super-proyek daripada masuk ke submodule.

Temukan Komitmen Pelanggaran proyek-Super

$ 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, sepertinya sudah rusak ce5d37c, jadi kami akan mengembalikan submodule dari induknya ( ce5d37c~).

Atau, Anda dapat mengambil komit submodul dari teks tambalan ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) dan menggunakan proses "dalam, luar" di atas.

Checkout di proyek-Super

$ git checkout ce5d37c~ -- sub

Ini mengatur ulang entri submodule untuk submelakukan apa yang dilakukan ce5d37c~di super-proyek.

Perbarui Submodule

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

Pembaruan submodule berjalan OK (ini menunjukkan HEAD terlepas).

Periksa hasilnya

$ 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

Perbedaan pertama menunjukkan bahwa subsekarang sama di ce5d37c~. Perbedaan kedua menunjukkan bahwa indeks dan tabel kerja adalah sama. Dif ketiga menunjukkan satu-satunya perubahan bertahap adalah memindahkan subsubmodule ke komit yang berbeda.

Melakukan

git commit

Ini melakukan entri submodul yang diperbaiki.

Chris Johnsen
sumber
Dalam pendekatan "Luar, Dalam", bisakah Anda menjelaskan mengapa "sepertinya itu buruk di ce5d37c?" Jari apa yang dilakukan orang jahat?
Garrett Albright
5
@ Garrett: Asumsinya adalah e47c0akomit yang tidak ada di repositori lokal untuk sub, namun super-proyek submenunjuk ke komit itu. Ini mungkin terjadi karena orang lain yang dibuat e47c0adalam salinan mereka sub, memperbarui proyek-super mereka untuk menunjukkan komitmen itu dan mendorong proyek-super tanpa mendorong e47c0ake repositori pusat / bersama sub. Ketika kita tarik dari pusat / bersama super-proyek kita mendapatkan komit yang poin subke e47c0a, tapi kami tidak bisa “melihat” yang melakukan. ce5d37cdicurigai karena, berdasarkan diff, itu diperkenalkan e47c0a.
Chris Johnsen
Itu masih agak kabur di mana hash spesifik subdisimpan di repo induk yang memilikinya sebagai submodule, dan apakah itu dapat dimanipulasi langsung ke KEPALA saat ini subsecara langsung, tanpa bergantung pada keadaan yang lebih tua dari induk repo, yang mungkin tidak selalu membantu.
matanster
187

coba ini:

git submodule sync
git submodule update
Lonre Wang
sumber
2
Sayangnya, bukan untuk saya, salah satu submodul kami menjadi target repositori utama git dengan perintah add, yang sekarang mengalami kesulitan untuk membatalkannya
Daniel
9
Bekerja untuk saya juga. Ingin tahu mengapa.
BenBtg
12
Ternyata melakukan git submodule syncitu diperlukan dalam skenario di mana URL remote untuk submodule yang diberikan telah berubah. Dalam kasus kami, kami telah menambahkan submodule kami dari repo publik dan kemudian mengubah URL ke garpu pribadi - dan memasukkan diri ke acar khusus ini.
Samscam
Sebagai contoh: Saya memiliki repo (A) yang diatur dengan submodule yang menunjuk ke repo github saya (B). Saya membuat cabang di repo A karena saya ingin menunjuk B di github repo orang lain. Setelah sedikit berjuang dengan itu dan melakukan cabang, saya mengganti repo A saya kembali ke master dan memiliki masalah ini dengan repo B. Solusi @Lonre Wang memperbaikinya.
fbicknel
2
Dengan asumsi tidak ada yang BENAR-BENAR mengacaukan (dalam hal ini Anda akan membutuhkan jawaban yang sangat baik oleh Chris Johnsen) jawaban oleh Lonre Wang harus memperbaiki masalahnya, ... KECUALI submodul Anda memiliki submodulnya sendiri (dan masalahnya ada di dalam submodul). Dalam hal ini Anda perlu cd ke submodule yang memiliki submodule dengan masalah dan menjalankan perintah di atas. Perhatikan bahwa pembaruan memiliki opsi --recursive (pembaruan git submodule --recursive), tetapi sinkronisasi tidak; Anda benar-benar harus menjalankan 'git submodule sync' secara manual di dalam submodule yang memiliki sub (sub) modul yang bermasalah. Ini masalah saya;).
Carlo Wood
16

Kesalahan ini dapat berarti bahwa komit tidak ada dalam submodule. Yaitu, repositori (A) memiliki submodule (B). A ingin memuat B sehingga menunjuk ke komit tertentu (dalam B). Jika komit itu entah bagaimana hilang, Anda akan mendapatkan kesalahan itu. Setelah kemungkinan penyebabnya: referensi ke komit didorong dalam A, tetapi komit sebenarnya tidak didorong dari B. Jadi saya akan mulai dari sana.

Kemungkinan kecil, ada masalah izin, dan komit tidak dapat ditarik (mungkin jika Anda menggunakan git + ssh).

Pastikan path submodule terlihat ok di .git / config dan .gitmodules.

Satu hal terakhir untuk dicoba - di dalam direktori submodule: git reset HEAD --hard

Daniel Tsadok
sumber
3
Saya sudah menjelaskan bahwa dalam pertanyaan ... pertanyaan itu sendiri adalah bagaimana menyelesaikannya. Dan sudah berhasil dijawab hampir dua tahun lalu ... Izin tidak ada hubungannya dengan ini.
Mauricio Scheffer
1
Anda menyatakannya, Anda tentu tidak menjelaskannya.
Daniel Tsadok
Maksud saya adalah, jawaban ini tidak menambahkan informasi berharga, saya akan menghapusnya.
Mauricio Scheffer
4
"git reset HEAD --hard" membantu saya juga ... tidak ada yang berhasil. Saya mencoba solusi sebelumnya juga, tidak ada dadu. Terima kasih!
Virgil
1
Setiap utas adalah dunia dunianya sendiri. Apa yang Anda katakan mewakili Anda - Anda tidak dapat berharap bahwa orang akan mempelajari sejarah pribadi Anda untuk mencoba membingkai komentar Anda dalam konteks yang memberi Anda rasa hormat yang Anda inginkan. Bersikap baik, hormat, dan Anda tidak perlu meminta orang untuk memahami kebiasaan pribadi Anda. Jika Anda dapat membaca komentar Anda dari konteks netral, seperti yang dilakukan orang luar, Anda akan memahami kritik saya.
Stabledog
10

Kemungkinan penyebabnya

Ini dapat terjadi ketika:

  1. Submodule telah diedit pada tempatnya
  2. Submodule (s) berkomitmen, yang memperbarui hash dari submodule yang ditunjuk
  3. Submodule tidak didorong .

misalnya sesuatu seperti ini terjadi:

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

Seharusnya submodule didorong pada saat ini.

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

Akibatnya, komit yang hilang tidak dapat ditemukan oleh pengguna jarak jauh karena mereka masih ada di disk lokal.

Larutan

Informasikan orang yang memodifikasi submodule untuk mendorong, yaitu

$ cd submodule
$ git push
chriskelly
sumber
6

Saya mendapatkan kesalahan ini ketika saya melakukannya:

$ git submodule update --init --depth 1

tetapi komit dalam proyek induk menunjuk pada komit sebelumnya.

Menghapus folder submodule dan menjalankan:

$ git submodule update --init

TIDAK menyelesaikan masalah. Saya menghapus repo dan mencoba lagi tanpa bendera yang dalam dan berhasil.

Kesalahan ini terjadi di Ubuntu 16.04 git 2.7.4, tetapi tidak pada Ubuntu 18.04 git 2.17, TODO menemukan perbaikan yang tepat pada komit atau versi.

Plato
sumber
tim saya sejak itu telah meninggalkan submodules dalam kode kami terlalu banyak kesulitan lol
Plato
1
apa alternatifmu?
nuzzolilo
@nuzzolilo yang kami tambahkan username/repo#shake package.json, opsi yang jauh lebih fleksibel adalah mengatur sistem Anda dengan seperangkat wadah buruh pelabuhan
Plato
3
Ini sangat menjengkelkan. --depth=1menghemat banyak bandwidth saat saya tidak membutuhkan riwayat repo. Jika ada yang menemukan atau tahu mengapa ini terjadi, saya ingin tahu.
i336_
@ i336_ Walaupun saya tidak bisa menjelaskan mengapa, saya telah menulis pembantu cmake yang membantu mengurangi masalah di sini: github.com/LMMS/lmms/blob/… . Ia menggunakan deinitpendekatan yang memperbaiki masalah sebagian besar waktu. Ketika dibundel dengan sistem build, pengguna akhir dapat membiarkan sistem build mengambil submodul dan membuang recursiveperintah yang rusak sama sekali. Masih ada skenario di mana ini rusak, seperti submodule telah melakukan push force dan menghapus komit sama sekali.
tresf
5

Ini juga dapat terjadi ketika Anda memiliki submodule yang menunjuk ke repositori yang telah direstrukturisasi dan komit yang diberikan "hilang". Meskipun komit masih dalam repositori jarak jauh, komit tidak ada dalam cabang. Jika Anda tidak dapat membuat cabang baru (mis. Bukan repositori Anda), Anda harus memperbarui proyek super untuk menunjuk komit baru. Atau Anda dapat mendorong salah satu salinan submodul Anda di tempat lain dan kemudian memperbarui proyek-super untuk menunjuk ke repositori itu.

pasamio
sumber
5

Cabang Anda mungkin tidak mutakhir, solusi sederhana tetapi cobalah git fetch

kittycatbytes
sumber
2

Jawaban ini untuk pengguna SourceTree dengan pengalaman terminal git terbatas.

Buka submodule yang bermasalah dari dalam proyek Git (proyek-super).

Ambil dan pastikan 'Ambil semua tag' dicentang.

Rebase, tarik proyek Git Anda.

Ini akan menyelesaikan masalah 'referensi bukan pohon' 9 dari sepuluh kali. 1 kali itu tidak akan, adalah perbaikan terminal seperti yang dijelaskan oleh jawaban teratas.

ericTear
sumber
1

Riwayat submodule Anda tetap tersimpan dengan aman di submodule git.

Jadi, mengapa tidak menghapus saja submodule dan menambahkannya lagi?

Jika tidak, apakah Anda mencoba mengedit secara manual HEADatau di refs/master/headdalam submodule.git

Lakshman Prasad
sumber
1
Ini tidak akan berhasil, karena di suatu tempat ada referensi ke 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 yang hanya ada di repo lokal di tempat lain, tetapi tidak dipublikasikan
Mauricio Scheffer
1

Untuk memastikannya, coba perbarui gitbinari Anda .

GitHub untuk Windows memiliki versi git version 1.8.4.msysgit.0yang dalam kasus saya adalah masalahnya. Pembaruan menyelesaikannya.

Gman
sumber
1

Dalam kasus saya, tidak ada jawaban di atas yang menyelesaikan masalah bahkan meskipun mereka adalah jawaban yang baik. Jadi saya memposting solusi saya (dalam kasus saya ada dua klien git, klien A dan B):

  1. pergi ke dir submodule:

    cd sub
    
  2. checkout ke master:

    git checkout master
    
  3. rebase ke kode komit yang bisa dilihat oleh kedua klien

  4. kembali ke dir induk:

  5. berkomitmen untuk menguasai

  6. ubah ke klien lain, lakukan rebaselagi.

  7. akhirnya berhasil sekarang! Mungkin kehilangan beberapa komitmen tetapi berhasil.

  8. FYI, jangan mencoba untuk menghapus submodule Anda, itu akan tetap .git/modulesada dan tidak dapat membaca submodule ini lagi, kecuali jika reaktif lokal.

kimimaro
sumber
1

Untuk menyinkronkan repo git dengan kepala submodule, jika itu benar-benar yang Anda inginkan, saya menemukan bahwa menghapus submodule dan kemudian membacanya menghindari menghindari bermain-main dengan sejarah. Sayangnya menghapus submodule membutuhkan peretasan alih-alih menjadi perintah git tunggal, tetapi bisa dilakukan.

Langkah-langkah yang saya ikuti untuk menghapus submodule, terinspirasi oleh https://gist.github.com/kyleturner/1563153 :

  1. Jalankan git rm --cached
  2. Hapus baris yang relevan dari file .gitmodules.
  3. Hapus bagian yang relevan dari .git / config.
  4. Hapus file submodule yang sekarang tidak dilacak.
  5. Hapus direktori .git / modules /

Sekali lagi, ini bisa berguna jika semua yang Anda inginkan adalah menunjuk ke kepala submodule lagi, dan Anda belum mempersulit hal dengan perlu menjaga salinan lokal dari submodule tetap utuh. Ini mengasumsikan Anda memiliki submodule "benar" sebagai repo sendiri, di mana pun asalnya, dan Anda hanya ingin kembali ke benar termasuk itu sebagai submodule.

Catatan: selalu membuat salinan lengkap dari proyek Anda sebelum melakukan manipulasi semacam ini atau perintah git di luar komit atau dorongan sederhana. Saya akan menyarankan itu dengan semua jawaban lain juga, dan sebagai pedoman umum git.

matanster
sumber
1

Baru saja menemukan masalah ini, dan tidak ada solusi yang bekerja untuk saya. Apa yang ternyata menjadi solusi untuk masalah saya sebenarnya jauh lebih sederhana: upgrade Git. Milik saya adalah 1.7.1, dan setelah saya memutakhirkannya menjadi 2.16.1 (terbaru), masalahnya hilang tanpa jejak! Kira saya meninggalkannya di sini, semoga membantu seseorang.

Phan
sumber