Errore 'riferimento non è un albero' della testa del sottomodulo Git


305

Ho un progetto con un sottomodulo che punta a un commit non valido: il commit del sottomodulo è rimasto locale e quando provo a recuperarlo da un altro repository ottengo:

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

So cosa TESTA modulo dovrebbe essere, c'è un modo per cambiare questo a livello locale, senza spingere dal repo che fa hanno commettere 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Non sono sicuro di essere chiaro ... ecco una situazione simile che ho trovato.


11
"fatale: il riferimento non è un albero" in riferimento ai sottomoduli sembra generalmente significare che il commit del sottomodulo che il repository padre si aspetta non sia stato ancora spinto, o che sia rovinato in qualche altro modo. Per noi questo confuso messaggio di errore è stato risolto semplicemente spingendo un sottomodulo che qualcuno ha dimenticato di inviare.
Chris Moschini,

1
@ChrisMoschini - Ho appena avuto quel problema, e questa era la mia "soluzione", ho spinto e tirato il repository principale, ma ho dimenticato di inviare il mio ultimo commit al repository del sottomodulo. Grazie!
Rotem,

Forse hai dimenticato di inviare l'ultimo commit del sottomodulo
Hafenkranich,

Risposte:


378

Supponendo che il repository del sottomodulo contenga un commit che si desidera utilizzare (diversamente dal commit a cui fa riferimento lo stato corrente del super-progetto), ci sono due modi per farlo.

Il primo richiede di conoscere già il commit dal sottomodulo che si desidera utilizzare. Funziona da "dentro, fuori" regolando direttamente il sottomodulo e quindi aggiornando il super-progetto. Il secondo funziona dall'esterno, trovando il commit del super-progetto che ha modificato il sottomodulo e quindi reimpostando l'indice del super-progetto per fare riferimento a un diverso commit del sottomodulo.

Alla rovescia

Se sai già che impegnano si desidera che il modulo per l'uso, cdal modulo, controllare il impegnano desiderato, quindi git adde git commitindietro nel super-progetto.

Esempio:

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

Spiacenti, qualcuno ha eseguito un commit di super-progetto che fa riferimento a un commit non pubblicato nel sottomodulo sub. In qualche modo, sappiamo già che vogliamo che il sottomodulo sia in commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Vai lì e dai un'occhiata direttamente.

Acquista nel sottomodulo

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

Dal momento che stiamo verificando un commit, questo produce un HEAD distaccato nel sottomodulo. Se si desidera assicurarsi che il sottomodulo stia utilizzando un ramo, utilizzare git checkout -b newbranch <commit>per creare e verificare un ramo al commit o verificare il ramo desiderato (ad es. Uno con il commit desiderato in punta).

Aggiorna il Super-progetto

Un checkout nel sottomodulo si riflette nel super-progetto come una modifica all'albero di lavoro. Quindi dobbiamo mettere in scena il cambiamento nell'indice del super-progetto e verificare i risultati.

$ git add sub

Controlla i risultati

$ 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

L'aggiornamento del sottomodulo era silenzioso perché il sottomodulo è già al commit specificato. Il primo diff mostra che l'indice e il worktree sono uguali. Il terzo diff mostra che l'unica modifica a fasi è lo spostamento del subsottomodulo su un commit diverso.

Commettere

git commit

Ciò commette la voce del sottomodulo fissa.


Fuori dentro

Se non si è sicuri del commit da utilizzare dal sottomodulo, è possibile consultare la cronologia nel superprogetto per guidare l'utente. Puoi anche gestire il reset direttamente dal super-progetto.

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

Questa è la stessa situazione di cui sopra. Ma questa volta ci concentreremo sul ripararlo dal super-progetto anziché immergerlo nel sottomodulo.

Trova Errant Commit del Super-progetto

$ 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, sembra che sia andato male ce5d37c, quindi ripristineremo il sottomodulo dal suo genitore ( ce5d37c~).

In alternativa, puoi prendere il commit del sottomodulo dal testo della patch ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) e usare invece il processo "dentro, fuori" sopra.

Acquista nel Super-progetto

$ git checkout ce5d37c~ -- sub

Ciò ha reimpostato la voce del sottomodulo per subciò che era in commit ce5d37c~nel super-progetto.

Aggiorna il sottomodulo

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

L'aggiornamento del sottomodulo è andato bene (indica una HEAD staccata).

Controlla i risultati

$ 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

Il primo diff mostra che subora è lo stesso in ce5d37c~. Il secondo diff mostra che l'indice e il worktree sono uguali. Il terzo diff mostra che l'unica modifica a fasi è lo spostamento del subsottomodulo in un diverso commit.

Commettere

git commit

Ciò commette la voce del sottomodulo fissa.


Nell'approccio "Outside, In", potresti chiarire perché "sembra che sia andato male in ce5d37c?" Che dita quella come cattiva commessa?
Garrett Albright,

5
@Garrett: il presupposto è che e47c0aun commit non esiste nel repository locale per sub, ma il super-progetto subpunta a quel commit. Questo potrebbe essere accaduto perché qualcun altro ha creato e47c0anella loro copia di sub, aggiornato il proprio super-progetto per puntare a quel commit e ha spinto il super-progetto senza spingere e47c0anel repository centrale / condiviso per sub. Quando noi tiriamo dal / shared super-progetto centrale otteniamo un commit che i punti suba e47c0a, ma non possiamo “vedere” che commettono. ce5d37cè sospetto perché, in base al diff, ha introdotto e47c0a.
Chris Johnsen,

È ancora piuttosto vago dove si trova l'hash specifico del submantenuto nel repository principale che lo ha come sottomodulo e se può essere manipolato direttamente nell'attuale HEAD subdirettamente, senza fare affidamento su uno stato precedente del genitore repo, che potrebbe non essere sempre d'aiuto.
matanster


187

prova questo:

git submodule sync
git submodule update

2
Purtroppo per me, uno dei nostri sottomoduli è stato preso di mira dal repository git principale con un comando add, ora avendo problemi a annullarlo
Daniel

9
Ha funzionato anche per me. Mi piacerebbe sapere perché.
BenBtg,

12
Si scopre che fare un git submodule syncè necessario negli scenari in cui l'URL del telecomando per un dato sottomodulo è cambiato. Nel nostro caso abbiamo aggiunto il nostro sottomodulo da un repository pubblico e quindi modificato l'URL in un fork privato - e ci siamo immersi in questo particolare pickle.
Samscam,

Ad esempio: avevo un repository (A) impostato con un sottomodulo che punta al mio repo github (B). Ho creato un ramo nel repository A perché volevo indicare B al repository github di qualcun altro. Dopo aver lottato un po 'con questo e aver impegnato il ramo, ho riportato il repository A in master e ho riscontrato questo problema con il repository B. La soluzione di @Lonre Wang l'ha risolto.
fbicknel,

2
Supponendo che nessuno VERAMENTE rovinato (nel qual caso avresti bisogno dell'eccellente risposta di Chris Johnsen), la risposta di Lonre Wang dovrebbe risolvere il problema, ... A MENO CHE i tuoi sottomoduli non abbiano i loro sottomoduli (e il problema è all'interno di un sottomodulo). In tal caso è necessario eseguire il cd nel sottomodulo che presenta il sottomodulo con il problema ed eseguire i comandi sopra. Nota che l'aggiornamento ha un'opzione --recursive (git submodule update --recursive), ma la sincronizzazione no; devi davvero eseguire manualmente 'git submodule sync' all'interno del sottomodulo che ha il sottom (sub) modulo problematico. Questo era il mio problema;).
Carlo Wood,

16

Questo errore può indicare che manca un commit nel sottomodulo. Cioè, il repository (A) ha un sottomodulo (B). A vuole caricare B in modo che indichi un certo commit (in B). Se quel commit è in qualche modo mancante, otterrai quell'errore. Una volta possibile causa: il riferimento al commit è stato inserito in A, ma il commit effettivo non è stato inviato da B. Quindi inizierei da lì.

Meno probabilmente, c'è un problema con le autorizzazioni e il commit non può essere tirato (possibile se stai usando git + ssh).

Assicurati che i percorsi dei sottomoduli appaiano bene in .git / config e .gitmodules.

Un'ultima cosa da provare - all'interno della directory del sottomodulo: git reset HEAD --hard


3
Ho già spiegato che nella domanda ... la domanda stessa era come risolverlo. Ed è già stato risposto con successo quasi due anni fa ... Le autorizzazioni non hanno nulla a che fare con questo.
Mauricio Scheffer,

1
L'hai dichiarato, di certo non l'hai spiegato.
Daniel Tsadok,

Il punto è che questa risposta non aggiunge alcuna informazione preziosa, la eliminerei.
Mauricio Scheffer,

4
anche il "git reset HEAD --hard" mi ha aiutato ... nient'altro ha funzionato. Ho provato anche le soluzioni precedenti, senza dadi. Grazie!
Virgilio,

1
Ogni thread è il suo piccolo mondo online. Quello che dici ti rappresenta: non puoi aspettarti che le persone studieranno la tua storia personale per cercare di inquadrare i tuoi commenti in un contesto che ti garantisca il rispetto che desideri. Sii gentile, rispettoso e non avrai bisogno di chiedere alle persone di capire le tue stranezze personali. Se riesci a leggere il tuo commento da un contesto neutrale, come farebbe un estraneo, capirai le mie critiche.
Stabledog

10

Causa possibile

Questo può succedere quando:

  1. I sottomoduli sono stati modificati sul posto
  2. Sottomodulo (i) sottoposto a commit, che aggiorna l'hash del sottomodulo indicato
  3. Sottomodulo (i) non inviato .

ad esempio qualcosa di simile è successo:

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

A questo punto avrebbe dovuto spingere il sottomodulo.

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

Di conseguenza, gli commit mancanti non possono essere trovati dall'utente remoto perché si trovano ancora sul disco locale.

Soluzione

Informa la persona che ha modificato il sottomodulo per inviare, ad es

$ cd submodule
$ git push

6

Ho ricevuto questo errore quando ho fatto:

$ git submodule update --init --depth 1

ma il commit nel progetto principale puntava a un commit precedente.

Eliminazione della cartella del sottomodulo ed esecuzione:

$ git submodule update --init

NON ha risolto il problema. Ho eliminato il repository e riprovato senza il flag di profondità e ha funzionato.

Questo errore si verifica in Ubuntu 16.04 git 2.7.4, ma non in Ubuntu 18.04 git 2.17, TODO trova il commit o la versione esatti.


da allora il mio team ha abbandonato i sottomoduli nel nostro codice in modo troppo seccante lol
Platone,

1
qual è stata la tua alternativa?
nuzzolilo,

@nuzzolilo che abbiamo aggiunto username/repo#shaa package.json, un'opzione molto più flessibile è quella di organizzare il tuo sistema con un set di container docker
Platone,

3
Questo è così fastidioso. --depth=1salva così tanta larghezza di banda quando non ho bisogno della cronologia dei repository. Se qualcuno trova o sa perché sta accadendo, mi piacerebbe saperlo.
i336_

@ i336_ Anche se non riesco a spiegare perché, ho scritto un aiuto cmake che aiuta a mitigare il problema qui: github.com/LMMS/lmms/blob/… . Utilizza un deinitapproccio che risolve il problema la maggior parte delle volte. Se associato a un sistema di build, l'utente finale può semplicemente lasciare che il sistema di build recuperi i sottomoduli e annulli completamente il recursivecomando rotto . Ci sono ancora scenari in cui questo si interrompe, come il sottomodulo ha fatto una spinta forzata e spazzato via del tutto il commit.
Tresf

5

Questo può accadere anche quando si ha un sottomodulo che punta a un repository che è stato ridisegnato e il commit dato è "sparito". Mentre il commit potrebbe essere ancora nel repository remoto, non si trova in un ramo. Se non riesci a creare un nuovo ramo (ad es. Non il tuo repository), sei bloccato con la necessità di aggiornare il super progetto per puntare a un nuovo commit. In alternativa puoi spingere una delle tue copie dei sottomoduli altrove e quindi aggiornare il super-progetto in modo che punti a quel repository.


5

La tua filiale potrebbe non essere aggiornata, una soluzione semplice ma prova git fetch


2

Questa risposta è per gli utenti di SourceTree con esperienza git terminale limitata.

Aprire il sottomodulo problematico dall'interno del progetto Git (superprogetto).

Recupera e assicurati che "Recupera tutti i tag" sia selezionato.

Rebase tira il tuo progetto Git.

Ciò risolverà il problema "riferimento non è un albero" 9 su dieci volte. Quella volta che non lo farà, è una correzione terminale come descritto dalla risposta principale.


1

La cronologia del tuo sottomodulo viene comunque conservata in modo sicuro nel git del sottomodulo.

Quindi, perché non eliminare semplicemente il sottomodulo e aggiungerlo di nuovo?

Altrimenti, hai provato a modificare manualmente HEADo refs/master/headall'interno del sottomodulo.git


1
Questo non funzionerà, perché da qualche parte c'è un riferimento a 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 che è solo nel repository locale da qualche altra parte, ma non pubblicato
Mauricio Scheffer

1

Per sicurezza, prova ad aggiornare i tuoi gitbinari.

GitHub per Windows ha la versione git version 1.8.4.msysgit.0che nel mio caso era il problema. Aggiornamento risolto.


1

Nel mio caso, nessuna delle risposte sopra risolve il problema anche se sono buone risposte. Quindi inserisco la mia soluzione (nel mio caso ci sono due client git, client A e B):

  1. vai alla directory del sottomodulo:

    cd sub
    
  2. checkout per padroneggiare:

    git checkout master
    
  3. rifare ad un codice di commit che entrambi i client possono vedere

  4. tornare alla directory del genitore:

  5. impegnarsi a padroneggiare

  6. passare all'altro client , fare di rebasenuovo.

  7. finalmente funziona bene ora! Forse perde un paio di commit ma funziona.

  8. Cordiali saluti, non tentare di rimuovere il sottomodulo, rimarrà .git/moduleslì e non potrà rileggere nuovamente questo sottomodulo, se non quello locale reattivo.


1

Per sincronizzare il repository git con la testa del sottomodulo, nel caso sia proprio quello che vuoi, ho scoperto che rimuovere il sottomodulo e poi leggerlo evita di armeggiare con la cronologia. Sfortunatamente la rimozione di un sottomodulo richiede l'hacking piuttosto che essere un singolo comando git, ma fattibile.

I passaggi che ho seguito per rimuovere il sottomodulo, ispirato a https://gist.github.com/kyleturner/1563153 :

  1. Esegui git rm --cached
  2. Elimina le righe pertinenti dal file .gitmodules.
  3. Elimina la sezione pertinente da .git / config.
  4. Elimina i file del sottomodulo ora non tracciati.
  5. Rimuovere la directory .git / modules /

Ancora una volta, questo può essere utile se tutto ciò che vuoi è puntare di nuovo alla testa del sottomodulo e non hai complicato le cose, avendo bisogno di mantenere intatta la copia locale del sottomodulo. Presuppone che tu abbia il sottomodulo "giusto" come proprio repository, dovunque sia l'origine, e vuoi solo tornare a includerlo correttamente come sottomodulo.

Nota: crea sempre una copia completa del tuo progetto prima di iniziare questo tipo di manipolazione o qualsiasi comando git oltre al semplice commit o push. Lo consiglierei anche con tutte le altre risposte e come linea guida generale.


1

Mi sono appena imbattuto in questo problema e nessuna di queste soluzioni ha funzionato per me. Quello che si è rivelato essere la soluzione al mio problema è in realtà molto più semplice: aggiorna Git. Il mio era 1.7.1 e dopo averlo aggiornato a 2.16.1 (più recente), il problema è scomparso senza lasciare traccia! Immagino che lo lascerò qui, spero che aiuti qualcuno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.