Błąd „Odwołanie do głowy modułu podrzędnego Git nie jest drzewem”

305

Mam projekt z podmodułem, który wskazuje na niepoprawne zatwierdzenie: zatwierdzenie podmodułu pozostało lokalne i kiedy próbuję pobrać go z innego repozytorium, otrzymuję:

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

Wiem co HEAD modułem powinno być, czy jest jakiś sposób mogę zmienić lokalnie, bez pchania z repo, że robi się popełnić 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Nie jestem pewien, czy wszystko jest jasne ... oto podobna sytuacja, którą znalazłem.

Mauricio Scheffer
źródło
11
„fatal: referencja nie jest drzewem” w odniesieniu do submodułów wydaje się ogólnie oznaczać zatwierdzenie submodułu, którego oczekiwanie, że repozytorium rodzicielskie nie zostało jeszcze wypchnięte lub jest zepsute w inny sposób. Dla nas ten mylący komunikat o błędzie został rozwiązany przez popchnięcie podmodułu, o którym ktoś zapomniał pchnąć.
Chris Moschini
1
@ChrisMoschini - Właśnie miałem ten problem i to było moje „rozwiązanie”, nacisnąłem i wyciągnąłem główne repozytorium, ale zapomniałem wcisnąć moje ostatnie zatwierdzenie do repozytorium podmodułu. Dzięki!
Rotem,
Być może zapomniałeś wprowadzić najnowsze zatwierdzenia submodułu
Hafenkranich,

Odpowiedzi:

378

Zakładając, że repozytorium submodułu zawiera zatwierdzenie, którego chcesz użyć (w przeciwieństwie do zatwierdzenia, do którego odwołuje się bieżący stan superprojektu), istnieją dwa sposoby, aby to zrobić.

Pierwszy wymaga znajomości zatwierdzenia z podmodułu, którego chcesz użyć. Działa od „wewnątrz, na zewnątrz”, bezpośrednio dostosowując submoduł, a następnie aktualizując superprojekt. Drugi działa od „z zewnątrz”, znajdując zatwierdzenie super projektu, które zmodyfikowało podmoduł, a następnie resetuj indeks superprojektu, aby odnosił się do innego zatwierdzenia submodułu.

Na lewą stronę

Jeśli już wiesz, jakiego zatwierdzenia chcesz użyć cdw tym podmodule, sprawdź w tym podmenu, którego chcesz, a następnie git addi git commitponownie w super-projekcie.

Przykład:

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

Ups, ktoś wykonał zatwierdzenie super projektu, które odnosi się do niepublikowanego zatwierdzenia w podmodule sub. Jakoś wiemy już, że chcemy, aby podmoduł był na zatwierdzeniu 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Idź tam i sprawdź to bezpośrednio.

Kasa w podmodule

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

Ponieważ sprawdzamy zatwierdzenie, powoduje to odłączenie HEAD w submodule. Jeśli chcesz się upewnić, że submoduł używa gałęzi, użyj git checkout -b newbranch <commit>do utworzenia i pobrania gałęzi przy zatwierdzeniu lub wypłaty żądanej gałęzi (np. Takiej z żądanym zatwierdzeniem na końcu).

Zaktualizuj superprojekt

Kasa w podmodule znajduje odzwierciedlenie w superprojekcie jako zmiana w działającym drzewie. Musimy więc wprowadzić zmiany w indeksie superprojektu i zweryfikować wyniki.

$ git add sub

Sprawdź wyniki

$ 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

Aktualizacja submodułu była cicha, ponieważ submoduł jest już w określonym zatwierdzeniu. Pierwszy diff pokazuje, że indeks i drzewo robocze są takie same. Trzeci diff pokazuje, że jedyną zmianą etapową jest przeniesienie subsubmodułu do innego zatwierdzenia.

Popełnić

git commit

Zatwierdza to pozycję submodułu naprawionego.


Na zewnątrz, w

Jeśli nie jesteś pewien, którego zatwierdzenia powinieneś użyć z podmodułu, możesz przejrzeć historię w superprojekcie, aby cię poprowadzić. Możesz także zarządzać resetowaniem bezpośrednio z superprojektu.

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

To ta sama sytuacja, co powyżej. Ale tym razem skupimy się na naprawieniu go z superprojektu zamiast zanurzaniu się w submodule.

Znajdź błędne zobowiązanie superprojektu

$ 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, wygląda na to, że poszło źle ce5d37c, więc przywrócimy submoduł z jego elementu nadrzędnego ( ce5d37c~).

Alternatywnie możesz pobrać zatwierdzenie podmodułu z tekstu poprawki ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) i zamiast tego użyć powyższego procesu „wewnątrz, na zewnątrz”.

Zamówienie w Super-projekcie

$ git checkout ce5d37c~ -- sub

Spowoduje to zresetowanie wpisu podmodułu subdo tego, co było w zatwierdzeniu ce5d37c~w superprojekcie.

Zaktualizuj podmoduł

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

Aktualizacja podmodułu poszła OK (wskazuje na odłączoną GŁOWĘ).

Sprawdź wyniki

$ 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

Pierwszy diff pokazuje, że subjest teraz taki sam w ce5d37c~. Drugi plik różnic pokazuje, że indeks i drzewo robocze są takie same. Trzeci diff pokazuje, że jedyną zmianą etapową jest przeniesienie subsubmodułu do innego zatwierdzenia.

Popełnić

git commit

Zatwierdza to pozycję submodułu naprawionego.

Chris Johnsen
źródło
W podejściu „Na zewnątrz, w” możesz wyjaśnić, dlaczego „wygląda na to, że poszło źle w ce5d37c?” Jakie palce popełnia ten zły?
Garrett Albright,
5
@Garrett: Założeniem jest e47c0azatwierdzenie, które nie istnieje w lokalnym repozytorium sub, ale subpunkty super-projektu wskazują na to zatwierdzenie. Może się tak zdarzyć, ponieważ ktoś inny utworzył e47c0aw swojej kopii sub, zaktualizował swój superprojekt, aby wskazywał na to zatwierdzenie, i wypchnął superprojekt, nie pchając e47c0ado centralnego / wspólnego repozytorium sub. Kiedy ciągnąć od centralnego / wspólną super projektu otrzymujemy zobowiązują się, że punkty subdo e47c0a, ale nie możemy „zobaczyć”, które popełnił. ce5d37cjest podejrzany, ponieważ w oparciu o różnicę wprowadził e47c0a.
Chris Johnsen
Nadal pozostaje dość niejasne, gdzie jest określony skrót subprzechowywany w repozytorium nadrzędnym, który ma go jako podmoduł, i czy można nim manipulować bezpośrednio do bieżącego HEAD subbezpośrednio, bez polegania na starszym stanie rodzica repo, co nie zawsze może pomóc.
matanster
187

Spróbuj tego:

git submodule sync
git submodule update
Lonre Wang
źródło
2
Niestety nie dla mnie jeden z naszych podmodułów był atakowany przez główne repozytorium git za pomocą polecenia add, które ma teraz problemy z cofnięciem
Daniel
9
Pracowałem też dla mnie. Chciałbym wiedzieć, dlaczego.
BenBtg,
12
Okazuje się, że wykonanie a git submodule syncjest konieczne w scenariuszach, w których zmienił się adres URL pilota dla danego podmodułu. W naszym przypadku dodaliśmy nasz podmoduł z publicznego repozytorium, a następnie zmieniliśmy adres URL na prywatny widelec - i znaleźliśmy się w tym konkretnym pikle.
Samscam,
Na przykład: miałem skonfigurowane repo (A) z submodułem wskazującym na moje repozytorium github (B). W repozytorium A utworzyłem gałąź, ponieważ chciałem wskazać B na repozytorium github innej osoby. Po odrobinie zmagania się z tym i popełnieniu oddziału, przestawiłem moje repozytorium A z powrotem na master i miałem ten problem z repozytorium B. @Lonre Wang rozwiązał go.
fbicknel
2
Zakładając, że nikt NAPRAWDĘ nie spieprzył (w takim przypadku potrzebujesz doskonałej odpowiedzi Chrisa Johnsena), odpowiedź Lonre Wanga powinna rozwiązać problem, ... chyba że twoje submoduły mają własne submoduły (a problem jest w submodule). W takim przypadku musisz wykonać cd do podmodułu, który ma podmoduł z problemem i wykonać powyższe polecenia. Zauważ, że aktualizacja ma opcję --recursive (aktualizacja modułu podrzędnego git --recursive), ale synchronizacja nie; naprawdę musisz ręcznie uruchomić „git submodule sync” w submodule, który ma problematyczny moduł podrzędny. To był mój problem;).
Carlo Wood,
16

Ten błąd może oznaczać brak zatwierdzenia w podmodule. Oznacza to, że repozytorium (A) ma podmoduł (B). A chce załadować B, aby wskazywał na pewne zatwierdzenie (w B). Jeśli tego zatwierdzenia w jakiś sposób brakuje, pojawi się ten błąd. Kiedyś możliwa przyczyna: odwołanie do zatwierdzenia zostało wypchnięte w A, ale rzeczywiste zatwierdzenie nie zostało wypchnięte z B. Więc zacznę od tego.

Mniej prawdopodobne, że występuje problem z uprawnieniami i nie można wyciągnąć zatwierdzenia (możliwe, jeśli używasz git + ssh).

Upewnij się, że ścieżki submodułów wyglądają dobrze w .git / config i .gitmodules.

Ostatnią rzeczą do wypróbowania - w katalogu podmodułu: git reset HEAD --hard

Daniel Tsadok
źródło
3
Wyjaśniłem już, że w pytaniu ... samo pytanie dotyczyło sposobu jego rozwiązania. Odpowiedzi na to już prawie dwa lata temu ... Uprawnienia nie mają z tym nic wspólnego.
Mauricio Scheffer
1
Powiedziałeś to, na pewno tego nie wyjaśniłeś.
Daniel Tsadok
Chodzi mi o to, że ta odpowiedź nie dodaje żadnych cennych informacji, usunę ją.
Mauricio Scheffer
4
„git reset HEAD --hard” pomógł mi również… nic więcej nie działało. Próbowałem też poprzednich rozwiązań, bez kości. Dzięki!
Wergiliusz
1
Każdy wątek ma swój własny mały świat online. To, co mówisz, reprezentuje cię - nie możesz oczekiwać, że ludzie przestudiują twoją osobistą historię, aby spróbować sformułować twoje komentarze w kontekście, który da ci szacunek, którego pragniesz. Bądźcie uprzejmi, szanujcie i nie będziecie musieli prosić ludzi o wyrozumiałość odnośnie waszych osobistych dziwactw. Jeśli potrafisz przeczytać swój komentarz z neutralnego kontekstu, tak jak postronny, zrozumiesz moją krytykę.
Stabledog
10

Możliwa przyczyna

Może się to zdarzyć, gdy:

  1. Podmoduły zostały edytowane na miejscu
  2. Zatwierdzone moduły podrzędne, które aktualizują hash wskazanego podmodułu
  3. Podmoduły nie zostały wypchnięte .

np. stało się coś takiego:

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

W tym momencie powinien był być podmoduł.

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

W wyniku tego użytkownik zdalny nie mógł znaleźć brakujących zatwierdzeń, ponieważ nadal znajdują się one na dysku lokalnym.

Rozwiązanie

Poinformuj osobę, która zmodyfikowała podmoduł w celu wypchnięcia, tj

$ cd submodule
$ git push
chriskelly
źródło
6

Wystąpił ten błąd, gdy:

$ git submodule update --init --depth 1

ale zatwierdzenie w projekcie nadrzędnym wskazywało na wcześniejsze zatwierdzenie.

Usuwanie folderu submodułu i uruchamianie:

$ git submodule update --init

NIE rozwiązało problemu. Usunąłem repozytorium i spróbowałem ponownie bez flagi głębokości i zadziałało.

Ten błąd występuje w Ubuntu 16.04 git 2.7.4, ale nie w Ubuntu 18.04 git 2.17, TODO znajduje dokładne ustalenie zatwierdzenia lub wersji.

Platon
źródło
mój zespół od tego czasu porzucił podmoduły w naszym kodzie zbyt wiele kłopotów lol
Platon
1
jaka była twoja alternatywa?
nuzzolilo
@nuzzolilo dodaliśmy username/repo#shado package.json, o wiele bardziej elastyczną opcją jest zorganizowanie systemu za pomocą zestawu kontenerów dokerów
Plato
3
To takie denerwujące. --depth=1oszczędza tak dużo przepustowości, gdy nie potrzebuję historii repo. Jeśli ktoś kiedykolwiek znajdzie lub wie, dlaczego tak się dzieje, chciałbym wiedzieć.
i336_
@ i336_ Chociaż nie potrafię wyjaśnić dlaczego, napisałem pomocnika cmake, który pomaga złagodzić problem tutaj: github.com/LMMS/lmms/blob/… . Wykorzystuje deinitpodejście, które rozwiązuje problem przez większość czasu. W pakiecie z systemem kompilacji użytkownik końcowy może po prostu pozwolić systemowi kompilacji pobrać moduły podrzędne i recursiveporzucić całkowicie niedziałające polecenie. Nadal istnieją scenariusze, w których to się psuje, takie jak podmoduł, który naciskał na siłę i całkowicie kasował zatwierdzenie.
tresf
5

Może się to również zdarzyć, gdy podmoduł wskazuje repozytorium, które zostało ponownie bazowane, a dane zatwierdzenie „zniknęło”. Chociaż zatwierdzenie może nadal znajdować się w zdalnym repozytorium, nie znajduje się w gałęzi. Jeśli nie możesz utworzyć nowej gałęzi (np. Nie swojego repozytorium), utkniesz w potrzebie aktualizacji super projektu, aby wskazywał na nowe zatwierdzenie. Alternatywnie możesz przesunąć jedną ze swoich kopii podmodułów w inne miejsce, a następnie zaktualizować superprojekt, tak aby wskazywał na to repozytorium.

pasamio
źródło
5

Twój oddział może nie być aktualny, proste rozwiązanie, ale spróbuj git fetch

kittycatbytes
źródło
2

Ta odpowiedź jest dla użytkowników SourceTree z ograniczonym doświadczeniem git terminalowym.

Otwórz problematyczny submoduł z projektu Git (superprojekt).

Pobierz i upewnij się, że „Pobierz wszystkie tagi” jest zaznaczone.

Rebase wyciągnij swój projekt Git.

To rozwiąże problem „odniesienie nie jest drzewem” 9 na dziesięć razy. To, że 1 raz tego nie zrobi, jest naprawą terminala, jak opisano w górnej odpowiedzi.

ericTbear
źródło
1

W każdym razie historia twojego submodułu jest bezpiecznie zachowana w git submodulu.

Dlaczego więc nie usunąć submodułu i dodać go ponownie?

W przeciwnym razie Próbowałeś ręcznie edytując HEADlub refs/master/headwewnątrz modułem.git

Lakshman Prasad
źródło
1
To nie zadziała, ponieważ gdzieś jest odniesienie do 2d7cfbd09fc96c04c4c41148d44ed7778add6b43, który jest tylko w lokalnym repozytorium gdzieś indziej, ale nie opublikowany
Mauricio Scheffer
1

Dla pewności spróbuj zaktualizować swoje gitpliki binarne.

GitHub dla Windows ma wersję, git version 1.8.4.msysgit.0która w moim przypadku była problemem. Aktualizacja rozwiązała to.

Gman
źródło
1

W moim przypadku żadna z powyższych odpowiedzi nie rozwiązuje problemu, nawet jeśli są to dobre odpowiedzi. Więc zamieszczam swoje rozwiązanie (w moim przypadku są dwa klienty git, klient A i B):

  1. przejdź do katalogu submodułu:

    cd sub
    
  2. kasa do opanowania:

    git checkout master
    
  3. bazować na kodzie zatwierdzenia, który obaj klient widzi

  4. wróć do katalogu rodzica:

  5. zobowiązać się do opanowania

  6. zmień na drugiego klienta, zrób to rebaseponownie.

  7. w końcu teraz działa dobrze! Może stracę kilka zobowiązań, ale działa.

  8. Do Twojej wiadomości, nie próbuj usuwać swojego submodułu, pozostanie on .git/modulestam i nie będzie mógł odczytać tego submodułu ponownie, chyba że będzie reaktywny lokalny.

kimimaro
źródło
1

Aby zsynchronizować repozytorium git z głową submodułu, w przypadku, gdy naprawdę tego chcesz, odkryłem, że usunięcie tego modułu, a następnie jego odczytanie pozwala uniknąć majstrowania przy historii. Niestety usunięcie submodułu wymaga hakowania, a nie pojedynczego polecenia git, ale wykonalne.

Kroki, które wykonałem, aby usunąć submoduł, zainspirowany https://gist.github.com/kyleturner/1563153 :

  1. Uruchom git rm --cached
  2. Usuń odpowiednie linie z pliku .gitmodules.
  3. Usuń odpowiednią sekcję z .git / config.
  4. Usuń teraz nieśledzone pliki modułów podrzędnych.
  5. Usuń katalog .git / modules /

Ponownie, może to być przydatne, jeśli wszystko, czego chcesz, to ponownie wskazać głowę submodułu, a nie skomplikowałeś rzeczy, ponieważ musisz zachować lokalną kopię tego modułu. Zakłada się, że podmoduł ma „prawo” jako własne repozytorium, niezależnie od tego, skąd pochodzi, i po prostu chcesz wrócić do prawidłowego włączenia go jako submodułu.

Uwaga: zawsze wykonuj pełną kopię projektu przed przystąpieniem do tego rodzaju manipulacji lub jakiegokolwiek polecenia git poza zwykłym zatwierdzaniem lub wypychaniem. Radzę to również przy wszystkich innych odpowiedziach i jako ogólna wskazówka git.

matanster
źródło
1

Natknąłem się na ten problem i żadne z tych rozwiązań nie działało dla mnie. To, co okazało się rozwiązaniem mojego problemu, jest w rzeczywistości o wiele prostsze: uaktualnij Git. Mój był w wersji 1.7.1, a po uaktualnieniu go do wersji 2.16.1 (najnowszej) problem zniknął bez śladu! Chyba zostawiam to tutaj, mam nadzieję, że to komuś pomoże.

Phan
źródło