Git Submodul Kopf 'Referenz ist kein Baum' Fehler


305

Ich habe ein Projekt mit einem Submodul, das auf ein ungültiges Commit verweist: Das Submodul-Commit blieb lokal und wenn ich versuche, es von einem anderen Repo abzurufen, erhalte ich:

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

Ich weiß, was das Submodul HEAD sein sollte. Gibt es eine Möglichkeit, dies lokal zu ändern, ohne von dem Repo zu drücken, das Commit hat 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Ich bin mir nicht sicher, ob ich klar bin ... hier ist eine ähnliche Situation, die ich gefunden habe.


11
"fatal: Referenz ist kein Baum" in Bezug auf Submodule scheint im Allgemeinen zu bedeuten, dass das vom übergeordneten Repo erwartete Submodul-Commit noch nicht verschoben wurde oder auf andere Weise vermasselt wurde. Für uns wurde diese verwirrende Fehlermeldung behoben, indem nur ein Submodul gedrückt wurde, das jemand vergessen hatte zu drücken.
Chris Moschini

1
@ChrisMoschini - Ich hatte gerade dieses Problem, und das war meine "Lösung". Ich habe das Haupt-Repo gedrückt und gezogen, aber ich habe vergessen, mein letztes Commit auf das Repo des Submoduls zu übertragen. Vielen Dank!
Rotem

Vielleicht haben Sie vergessen, die neuesten Submodul-Commits zu pushen
Hafenkranich

Antworten:


378

Angenommen, das Repository des Submoduls enthält ein Commit, das Sie verwenden möchten (im Gegensatz zu dem Commit, auf das aus dem aktuellen Status des Superprojekts verwiesen wird), gibt es zwei Möglichkeiten.

Das erste erfordert, dass Sie das Commit bereits von dem Submodul kennen, das Sie verwenden möchten. Es funktioniert von innen nach außen, indem das Submodul direkt angepasst und das Superprojekt aktualisiert wird. Der zweite Vorgang erfolgt von außen nach innen, indem das Commit des Superprojekts ermittelt wird, mit dem das Submodul geändert wurde, und anschließend der Index des Superprojekts zurückgesetzt wird, um auf ein anderes Commit des Submoduls zu verweisen.

Von innen nach außen

Wenn Sie bereits wissen, welches Commit das Submodul verwenden soll cd, überprüfen Sie das gewünschte Commit für das Submodul git addund git commitdann wieder im Superprojekt.

Beispiel:

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

Hoppla, jemand hat ein Superprojekt-Commit durchgeführt, das sich auf ein unveröffentlichtes Commit im Submodul bezieht sub. Irgendwie wissen wir bereits, dass das Submodul festgeschrieben werden soll 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Gehen Sie dorthin und sehen Sie es sich direkt an.

Kasse im Submodul

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

Da wir ein Commit auschecken, erzeugt dies einen getrennten HEAD im Submodul. Wenn Sie sicherstellen möchten, dass das Submodul einen Zweig verwendet git checkout -b newbranch <commit>, erstellen und checken Sie einen Zweig beim Festschreiben aus oder checken den gewünschten Zweig aus (z. B. einen mit dem gewünschten Festschreiben an der Spitze).

Aktualisieren Sie das Super-Projekt

Ein Checkout im Submodul spiegelt sich im Superprojekt als Änderung des Arbeitsbaums wider. Wir müssen also die Änderung im Index des Superprojekts inszenieren und die Ergebnisse überprüfen.

$ git add sub

Überprüfen Sie die Ergebnisse

$ 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

Die Aktualisierung des Submoduls war stumm, da sich das Submodul bereits im angegebenen Commit befindet. Der erste Unterschied zeigt, dass Index und Arbeitsbaum identisch sind. Der dritte subUnterschied zeigt, dass die einzige schrittweise Änderung darin besteht, das Submodul in ein anderes Commit zu verschieben.

Verpflichten

git commit

Dies schreibt den festen Submoduleintrag fest.


Außenseite nach innen

Wenn Sie nicht sicher sind, welches Commit Sie aus dem Submodul verwenden sollen, können Sie sich den Verlauf im Superprojekt ansehen, um sich zu orientieren. Sie können den Reset auch direkt vom Superprojekt aus verwalten.

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

Dies ist die gleiche Situation wie oben. Aber dieses Mal werden wir uns darauf konzentrieren, es aus dem Superprojekt heraus zu reparieren, anstatt in das Submodul einzutauchen.

Finden Sie das Errant Commit des Superprojekts

$ 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, es sieht so aus, als wäre es schlecht ce5d37cgelaufen, also werden wir das Submodul von seinem übergeordneten ( ce5d37c~) wiederherstellen .

Alternativ können Sie das Commit des Submoduls aus dem Patch-Text ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) übernehmen und stattdessen den obigen Prozess "Inside, Out" verwenden.

Kasse im Super-Projekt

$ git checkout ce5d37c~ -- sub

Dadurch wurde der Submoduleintrag subauf das zurückgesetzt , was er ce5d37c~im Superprojekt festgeschrieben hatte.

Aktualisieren Sie das Submodul

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

Das Submodul-Update ging in Ordnung (es zeigt einen abgetrennten HEAD an).

Überprüfen Sie die Ergebnisse

$ 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

Der erste Unterschied zeigt, dass dies subjetzt der gleiche ist ce5d37c~. Der zweite Unterschied zeigt, dass Index und Arbeitsbaum identisch sind. Der dritte subUnterschied zeigt, dass die einzige schrittweise Änderung darin besteht, das Submodul in ein anderes Commit zu verschieben.

Verpflichten

git commit

Dies schreibt den festen Submoduleintrag fest.


Können Sie im Ansatz "Outside, In" erläutern, warum "es so aussieht, als wäre es in ce5d37c schlecht gelaufen"? Welche Finger begeht dieser als der schlechte Commit?
Garrett Albright

5
@ Garrett: Die Annahme ist e47c0aein Commit, das im lokalen Repository für nicht vorhanden ist sub, aber das Superprojekt subverweist auf dieses Commit. Dies kann geschehen sein, weil jemand anderes, der e47c0ain seiner Kopie von erstellt wurde sub, sein Superprojekt aktualisiert hat, um auf dieses Commit zu verweisen, und das Superprojekt verschoben hat, ohne e47c0aauf das zentrale / gemeinsam genutzte Repository für zu pushen sub. Wenn wir von dem zentralen / shared super-Projekt ziehen bekommen wir eine Festschreibung , dass die Punkte subauf e47c0a, aber wir können nicht „sehen“ , die zu begehen. ce5d37cist verdächtig, weil es aufgrund des Diff eingeführt wurde e47c0a.
Chris Johnsen

Es bleibt noch ziemlich vage, wo sich der spezifische Hash des subim übergeordneten Repo aufbewahrten Repos befindet, der es als Submodul enthält, und ob es direkt auf den aktuellen HEAD von subdirekt manipuliert werden kann oder nicht , ohne sich auf einen älteren Status des Elternteils zu verlassen Repo, was vielleicht nicht immer hilft.
Matanster

@matanster: Es wird direkt in
Gits

187

Versuche dies:

git submodule sync
git submodule update

2
Leider nicht für mich, eines unserer Submodule wurde vom Haupt-Git-Repository mit einem Add-Befehl als Ziel ausgewählt und hat nun Probleme, es rückgängig zu machen
Daniel,

9
Hat auch für mich gearbeitet. Würde gerne wissen warum.
BenBtg

12
Es stellt sich heraus, dass dies git submodule syncin Szenarien erforderlich ist, in denen sich die URL der Fernbedienung für ein bestimmtes Submodul geändert hat. In unserem Fall hatten wir unser Submodul aus einem öffentlichen Repo hinzugefügt und dann die URL in eine private Abzweigung geändert - und uns in diese spezielle Essiggurke hineinversetzt.
Samscam

Zum Beispiel: Ich hatte ein Repo (A) eingerichtet, dessen Submodul auf mein Github-Repo (B) zeigte. Ich habe einen Zweig im Repo A erstellt, weil ich B auf das Github-Repo eines anderen zeigen wollte. Nachdem ich ein bisschen damit zu kämpfen hatte und den Zweig festlegte, schaltete ich mein Repo A wieder auf Master um und hatte dieses Problem mit Repo B. @Lonre Wangs Lösung hat es behoben.
Fbicknel

2
Angenommen, niemand hat es WIRKLICH vermasselt (in diesem Fall benötigen Sie eine ausgezeichnete Antwort von Chris Johnsen), sollte die Antwort von Lonre Wang das Problem beheben, ... WENN Ihre Submodule keine eigenen Submodule haben (und das Problem in einem Submodul liegt). In diesem Fall müssen Sie in das Submodul cd, das das Submodul mit dem Problem hat, und die obigen Befehle ausführen. Beachten Sie, dass das Update die Option --recursive hat (git submodule update --recursive), die Synchronisierung jedoch nicht. Sie müssen 'git submodule sync' wirklich manuell innerhalb des Submoduls ausführen, das das problematische Sub- (Sub-) Modul enthält. Das war mein Problem;).
Carlo Wood

16

Dieser Fehler kann bedeuten, dass ein Commit im Submodul fehlt. Das heißt, das Repository (A) hat ein Submodul (B). A möchte B so laden, dass es auf ein bestimmtes Commit zeigt (in B). Wenn dieses Commit irgendwie fehlt, wird dieser Fehler angezeigt. Einmal mögliche Ursache: Der Verweis auf das Commit wurde in A verschoben, aber das tatsächliche Commit wurde nicht von B übertragen. Also würde ich dort beginnen.

Weniger wahrscheinlich liegt ein Berechtigungsproblem vor und das Commit kann nicht gezogen werden (möglich, wenn Sie git + ssh verwenden).

Stellen Sie sicher, dass die Submodulpfade in .git / config und .gitmodules in Ordnung sind.

Eine letzte Sache, die Sie versuchen sollten - im Submodul-Verzeichnis: git reset HEAD --hard


3
Ich habe das bereits in der Frage erklärt ... die Frage selbst war, wie man es löst. Und es wurde bereits vor fast zwei Jahren erfolgreich beantwortet ... Berechtigungen haben damit nichts zu tun.
Mauricio Scheffer

1
Du hast es gesagt, du hast es bestimmt nicht erklärt.
Daniel Tsadok

Mein Punkt ist, diese Antwort fügt keine wertvollen Informationen hinzu, ich würde sie löschen.
Mauricio Scheffer

4
das "git reset HEAD --hard" hat mir auch geholfen ... sonst hat nichts funktioniert. Ich habe auch die vorherigen Lösungen ausprobiert, keine Würfel. Vielen Dank!
Virgil

1
Jeder Thread ist eine eigene kleine Welt online. Was Sie sagen, repräsentiert Sie - Sie können nicht erwarten, dass die Leute Ihre persönliche Geschichte studieren, um zu versuchen, Ihre Kommentare in einen Kontext zu stellen, der Ihnen den Respekt gewährt, den Sie sich wünschen. Seien Sie freundlich, respektvoll und Sie müssen die Leute nicht bitten, Ihre persönlichen Macken zu verstehen. Wenn Sie Ihren Kommentar aus einem neutralen Kontext lesen können, wie es ein Außenstehender tun würde, werden Sie meine Kritik verstehen.
Stabledog

10

Mögliche Ursache

Dies kann passieren, wenn:

  1. Submodule wurden an Ort und Stelle bearbeitet
  2. Festgeschriebene Submodule, die den Hash des Submoduls aktualisieren, auf das verwiesen wird
  3. Submodul (e) nicht gedrückt .

zB ist so etwas passiert:

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

Sollte das Submodul an dieser Stelle gedrückt haben.

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

Infolgedessen konnten die fehlenden Festschreibungen vom Remotebenutzer möglicherweise nicht gefunden werden, da sie sich noch auf der lokalen Festplatte befinden.

Lösung

Informieren Sie die Person, die das Submodul geändert hat, um zu pushen, dh

$ cd submodule
$ git push

6

Ich habe diesen Fehler bekommen, als ich tat:

$ git submodule update --init --depth 1

Das Commit im übergeordneten Projekt zeigte jedoch auf ein früheres Commit.

Löschen des Submodul-Ordners und Ausführen von:

$ git submodule update --init

hat das Problem NICHT gelöst. Ich habe das Repo gelöscht und es erneut ohne die Tiefenflagge versucht und es hat funktioniert.

Dieser Fehler tritt in Ubuntu 16.04 Git 2.7.4 auf, aber nicht in Ubuntu 18.04 Git 2.17. TODO findet das genaue Fixing Commit oder die Version.


Mein Team hat seitdem Submodule in unserem Code viel zu viel Aufwand aufgegeben lol
Plato

1
Was war deine Alternative?
Nuzzolilo

@nuzzolilo haben wir username/repo#shazu package.json hinzugefügt , eine viel flexiblere Option ist es, Ihr System mit einer Reihe von Docker-Containern zu organisieren
Plato

3
Das ist so nervig. --depth=1spart so viel Bandbreite, wenn ich den Repo-Verlauf nicht benötige. Wenn jemand jemals findet oder weiß, warum dies geschieht, würde ich es gerne wissen.
i336_

@ i336_ Obwohl ich nicht erklären kann, warum, habe ich einen cmake-Helfer geschrieben, der das Problem hier mildert: github.com/LMMS/lmms/blob/… . Es wird ein deinitAnsatz verwendet, der das Problem die meiste Zeit behebt. In Verbindung mit einem Build-System kann der Endbenutzer das Build-System einfach die Submodule abrufen lassen und den fehlerhaften recursiveBefehl ganz fallen lassen. Es gibt immer noch Szenarien, in denen dies unterbrochen wird, z. B. dass das Submodul einen Force-Push ausgeführt und das Commit vollständig gelöscht hat.
Tresf

5

Dies kann auch passieren, wenn ein Submodul auf ein Repository verweist, das neu basiert wurde, und das angegebene Commit "weg" ist. Während sich das Commit möglicherweise noch im Remote-Repository befindet, befindet es sich nicht in einem Zweig. Wenn Sie keinen neuen Zweig erstellen können (z. B. nicht Ihr Repository), müssen Sie das Superprojekt nicht mehr aktualisieren, um auf ein neues Commit zu verweisen. Alternativ können Sie eine Ihrer Kopien der Submodule an eine andere Stelle verschieben und dann das Superprojekt aktualisieren, um stattdessen auf dieses Repository zu verweisen.


5

Ihre Niederlassung ist möglicherweise nicht auf dem neuesten Stand, eine einfache Lösung, aber versuchen Sie es git fetch


2

Diese Antwort richtet sich an Benutzer von SourceTree mit eingeschränkter Erfahrung mit Terminal-Git.

Öffnen Sie das problematische Submodul aus dem Git-Projekt (Superprojekt).

Abrufen und sicherstellen, dass "Alle Tags abrufen" aktiviert ist.

Rebase ziehen Sie Ihr Git-Projekt.

Dies löst das Problem "Referenz ist kein Baum" 9 von zehn Fällen. Das 1 Mal, wenn dies nicht der Fall ist, ist ein Terminal-Fix, wie in der oberen Antwort beschrieben.


1

Ihr Submodulverlauf wird ohnehin sicher im Submodul-Git gespeichert.

Warum also nicht einfach das Submodul löschen und erneut hinzufügen?

Andernfalls haben Sie versucht, das HEADoder refs/master/headdas Submodul manuell zu bearbeiten.git


1
Dies wird nicht funktionieren, da irgendwo ein Verweis auf 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 vorhanden ist, der nur im lokalen Repo woanders, aber nicht veröffentlicht ist
Mauricio Scheffer

1

Versuchen Sie zur Sicherheit, Ihre gitBinärdateien zu aktualisieren .

GitHub für Windows hat die Version, git version 1.8.4.msysgit.0die in meinem Fall das Problem war. Aktualisierung gelöst.


1

In meinem Fall löst keine der oben genannten Antworten das Problem, auch wenn es sich um gute Antworten handelt. Also poste ich meine Lösung (in meinem Fall gibt es zwei Git-Clients, Client A und B):

  1. Gehe zum Verzeichnis des Submoduls:

    cd sub
    
  2. Kasse zum Master:

    git checkout master
    
  3. Rebase auf einen Commit-Code, den beide Clients sehen können

  4. gehe zurück zum Verzeichnis der Eltern:

  5. verpflichten sich zu meistern

  6. zum anderen Client wechseln rebaseagain erneut ausführen.

  7. endlich funktioniert es jetzt gut! Vielleicht ein paar Commits verlieren, aber es funktioniert.

  8. Zu Ihrer Information, versuchen Sie nicht, Ihr Submodul zu entfernen, es bleibt .git/modulesdort und kann dieses Submodul nicht erneut lesen, es sei denn, es ist ein reaktives lokales Modul.


1

Um das Git-Repo mit dem Kopf des Submoduls zu synchronisieren, habe ich festgestellt, dass das Entfernen und anschließende Lesen des Submoduls das Basteln mit dem Verlauf vermeidet, falls dies wirklich gewünscht wird. Leider erfordert das Entfernen eines Submoduls das Hacken, anstatt ein einzelner Git-Befehl zu sein, aber machbar.

Schritte zum Entfernen des Submoduls, inspiriert von https://gist.github.com/kyleturner/1563153 :

  1. Führen Sie git rm --cached aus
  2. Löschen Sie die relevanten Zeilen aus der .gitmodules-Datei.
  3. Löschen Sie den entsprechenden Abschnitt aus .git / config.
  4. Löschen Sie die jetzt nicht verfolgten Submodul-Dateien.
  5. Entfernen Sie das Verzeichnis .git / modules /

Dies kann wiederum nützlich sein, wenn Sie nur erneut auf den Kopf des Submoduls zeigen möchten und Sie die Dinge nicht kompliziert haben, indem Sie die lokale Kopie des Submoduls intakt halten müssen. Es wird davon ausgegangen, dass Sie das Submodul "richtig" als eigenes Repo haben, wo immer es seinen Ursprung hat, und Sie möchten es einfach wieder richtig als Submodul einbinden.

Hinweis: Erstellen Sie immer eine vollständige Kopie Ihres Projekts, bevor Sie diese Art von Manipulation oder einen Git-Befehl ausführen, der über das einfache Festschreiben oder Drücken hinausgeht. Ich würde das auch bei allen anderen Antworten und als allgemeine Git-Richtlinie empfehlen.


1

Ich bin gerade auf dieses Problem gestoßen, und keine dieser Lösungen hat bei mir funktioniert. Was sich als Lösung für mein Problem herausstellte, ist tatsächlich viel einfacher: Git aktualisieren. Meins war 1.7.1 und nachdem ich es auf 2.16.1 (aktuell) aktualisiert hatte, verschwand das Problem spurlos! Ich schätze, ich lasse es hier, hoffe es hilft jemandem.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.