L’errore “riferimento non è un albero” di Git submodule

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

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

So quale dovrebbe essere il sottomodulo HEAD, è ansible modificarlo localmente, senza spingere dal repository che ha commesso 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 ?

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

Supponendo che il repository del submodule contenga un commit che vuoi usare (a differenza del 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 aggiornando il super-progetto. Il secondo funziona da “outside, in” trovando il commit del super project che modifica il sottomodulo e quindi resetta l’indice del super-project per fare riferimento a un commit del submodule diverso.

Alla rovescia

Se sai già quale commit vuoi che il sottomodulo usi, git add cd al sottomodulo, controlla il commit che vuoi, quindi git add git commit e git commit lo rimanda 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 controlla 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  HEAD is now at 5d5a3ee... quux $ cd .. 

Dal momento che stiamo controllando un commit, questo produce un HEAD distaccato nel sottomodulo. Se vuoi assicurarti che il sottomodulo stia usando un ramo, usa git checkout -b newbranch per creare e git checkout -b newbranch un ramo al commit o controllare il ramo che vuoi (es. Uno con il commit desiderato sulla 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 dell’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 l’albero di lavoro sono gli stessi. La terza diff mostra che l’unica modifica graduale è lo spostamento del sottomodulo sub su un commit diverso.

Commettere

 git commit 

Commette la voce del sottomodulo fisso.


Fuori dentro

Se non si è sicuri di quale commit si dovrebbe utilizzare dal sottomodulo, è ansible consultare la cronologia nel superproject 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 invece di immergerci 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 in ce5d37c , quindi ripristineremo il sottomodulo dal suo genitore ( ce5d37c~ ).

In alternativa, puoi prendere il commit del submodule dal testo della patch ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c ) e utilizzare invece il processo “inside, out” sopra.

Acquista nel Super-progetto

 $ git checkout ce5d37c~ -- sub 

Questo ha ripristinato la voce del sottomodulo per sub in cosa consisteva 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 un HEAD distaccato).

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 sub è ora lo stesso in ce5d37c~ . La seconda diff mostra che l’indice e l’albero di lavoro sono gli stessi. La terza diff mostra che l’unica modifica graduale è lo spostamento del sottomodulo sub su un commit diverso.

Commettere

 git commit 

Commette la voce del sottomodulo fisso.

prova questo:

 git submodule sync git submodule update 

Questo errore può significare che manca un commit nel sottomodulo. Cioè, il repository (A) ha un sottomodulo (B). A vuole caricare B in modo che punti a un certo commit (in B). Se quel commit è in qualche modo mancante, otterrai questo errore. Una volta ansible causa: il riferimento al commit è stato inserito in A, ma il commit effettivo non è stato premuto da B. Quindi inizierei da lì.

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

Assicurati che i percorsi del sottomodulo siano ok in .git / config e .gitmodules.

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

Causa ansible

Questo può accadere quando:

  1. Il / i sottomodulo / i sono stati modificati sul posto
  2. Sottomodulo (i) impegnato, che aggiorna l’hash del sottomodulo puntato
  3. Sottomodulo (s) non spinto .

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!" 

Dovrebbe avere il sottomodulo premuto a questo punto.

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

Di conseguenza, non è stato ansible trovare i commit mancanti dall’utente remoto perché sono ancora sul disco locale.

Soluzione

Informa la persona che ha modificato il sottomodulo per spingere, es

 $ cd submodule $ git push 

Ciò può anche accadere quando si ha un sottomodulo che punta a un repository che è stato ridefinito e il commit specificato è “andato”. 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 a dover aggiornare il super progetto per puntare a un nuovo commit. In alternativa puoi spingere una delle tue copie dei sottomoduli altrove, quindi aggiornare il super-progetto in modo che punti invece a quel repository.

Ho ricevuto questo errore quando l’ho fatto:

 $ git submodule update --init --depth 1 

ma il commit nel progetto padre stava puntando a un commit precedente.
Eliminazione della cartella del sottomodulo ed esecuzione

 $ git submodule update --init 

NON ha risolto il problema. Ho cancellato il repository e ho provato di nuovo senza il flag di profondità e ha funzionato.

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

Apri il sottomodulo problematico all’interno del progetto Git (super-progetto).

Recupera e verifica che ‘Recupera tutti i tag’ sia selezionato.

Rebase tira il tuo progetto Git.

Ciò risolverà il problema del “riferimento non è un albero” 9 volte su 10. Quella volta che non lo farà, è una correzione terminale come descritto dalla risposta superiore.

La cronologia del tuo submodule è comunque conservata nel modulo sottotitolo.

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

Altrimenti, hai provato a modificare manualmente HEAD o refs/master/head nel sottomodulo .git

Per sicurezza, prova ad aggiornare i tuoi binari git .

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

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

  1. vai alla directory del submodule:

     cd sub 
  2. checkout per padroneggiare:

     git checkout master 
  3. rebase a un codice di commit che entrambi i client possono vedere

  4. torna alla directory del genitore:

  5. impegnarsi a padroneggiare

  6. passare all’altro client, rebase nuovo.

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

  8. Cordiali saluti, non provare a rimuovere il tuo sottomodulo, rimarrà .git/modules lì e non riesco più a leggere questo sottomodulo, a meno di uno locale reattivo.

Per sincronizzare il repository git con la testina del sottomodulo, nel caso che sia davvero quello che vuoi, ho scoperto che rimuovere il sottomodulo e 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.

Passi 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. Rimuovi la directory .git / modules /

Di nuovo, questo può essere utile se tutto ciò che vuoi è puntare di nuovo la testa del sottomodulo, e non hai complicato le cose avendo bisogno di mantenere intatta la copia locale del sottomodulo. Si presuppone che il sottomodulo “giusto” sia il proprio repository, ovunque l’origine sia, e si desidera semplicemente tornare a includerlo correttamente come sottomodulo.

Nota: fai sempre una copia completa del tuo progetto prima di impegnarti in 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 sul git.

Sono appena incappato in questo problema e nessuna di queste soluzioni ha funzionato per me. Quello che è risultato essere la soluzione per il mio problema è in realtà molto più semplice: aggiornare Git. Il mio era 1.7.1, e dopo averlo aggiornato a 2.16.1 (ultimo), il problema è andato via senza lasciare traccia! Suppongo che me ne stia andando qui, spero che aiuti qualcuno.