Git sous-module tête "de référence n'est pas un arbre" erreur
J'ai un projet avec un sous-module qui pointe vers un commit invalide: le commit du sous-module est resté local et quand j'essaie de le récupérer à partir d'un autre repo, je reçois:
$ git submodule update
fatal: reference is not a tree: 2d7cfbd09fc96c04c4c41148d44ed7778add6b43
Unable to checkout '2d7cfbd09fc96c04c4c41148d44ed7778add6b43' in submodule path 'mysubmodule'
Je sais ce que devrait être la tête du sous-module, est-il possible de changer cela localement, sans pousser du repo que fait avoir commit 2d7cfbd09fc96c04c4c41148d44ed7778add6b43
?
Je ne suis pas sûr d'être clair... voici une situation similaire j'ai trouvé.
12 réponses
En supposant que le référentiel du sous-module contient un commit que vous voulez utiliser (contrairement au commit qui est référencé à partir de l'état actuel du super-projet), il y a deux façons de le faire.
Le premier nécessite que vous connaissiez déjà le commit du sous-module que vous souhaitez utiliser. Il fonctionne à partir de "l'intérieur, l'extérieur" en ajustant directement le sous-module puis en mettant à jour le super-projet. Le second fonctionne de "l'extérieur, dans" en trouvant le commit du super-projet qui a modifié le sous-module, puis réinitialiser l'index du super-projet pour faire référence à un commit sous-module différent.
Intérieur, Extérieur
Si vous savez déjà qui commit, vous voulez que le sous-module à utiliser, cd
pour le sous-module, découvrez le commit que vous voulez, puis git add
et git commit
dans le super-projet.
Exemple:
$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'
Oups, quelqu'un a fait un commit de super-projet qui fait référence à un commit non publié dans le sous-module sub
. D'une certaine manière, nous savons déjà que nous voulons le sous-module à être à commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c
. Allez-y et vérifier directement.
Commander dans le sous-module
$ 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 ..
Puisque nous vérifions un commit, cela produit une tête détachée dans le sous-module. Si vous voulez vous assurer que le sous-module utilise une branche, utilisez git checkout -b newbranch <commit>
pour créer et extraire une branche à la validation ou extraire la branche que vous voulez (par exemple, une avec la validation souhaitée à la pointe).
Mettre à jour le Super-projet
Une caisse dans le sous-module est reflété dans le super-projet comme un changement à l'arbre de travail. Nous devons donc mettre en scène le changement dans l'index du super-projet et vérifier les résultats.
$ git add sub
Vérifiez les résultats
$ 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
La mise à jour du sous-module était silencieuse car le sous-module est déjà à la validation spécifiée. Le premier diff montre que l'index et l'arbre de travail sont les mêmes. Le troisième diff montre que le seul changement par étapes est de déplacer le sous-module sub
vers un autre engager.
Commettre
git commit
Cela valide l'entrée du sous-module fixe.
À L'Extérieur, Dans
Si vous n'êtes pas sûr du commit que vous devez utiliser à partir du sous-module, vous pouvez regarder l'historique dans le superprojet pour vous guider. Vous pouvez également gérer la réinitialisation directement à partir du super-projet.
$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'
C'est la même situation que ci-dessus. Mais cette fois, nous allons nous concentrer sur la fixation du super-projet au lieu de plonger dans le sous-module.
Trouver le Commit Errant du Super-projet
$ 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, on dirait que ça a mal tourné dans ce5d37c
, donc nous allons restaurer le sous-module de son parent (ce5d37c~
).
Alternativement, vous pouvez prendre le commit du sous-module à partir du texte du patch (5d5a3ee314476701a20f2c6ec4a53f88d651df6c
) et utiliser le processus "inside, out" ci-dessus à la place.
Commander dans le Super-projet
$ git checkout ce5d37c~ -- sub
Cela réinitialise l'entrée du sous-module pour sub
à ce qu'elle était à commit ce5d37c~
dans le super projet.
Mettre à jour le sous-module
$ git submodule update
Submodule path 'sub': checked out '5d5a3ee314476701a20f2c6ec4a53f88d651df6c'
La mise à jour du sous-module s'est bien passée (elle indique une tête détachée).
Vérifiez les résultats
$ 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
, Le premier diff montre que sub
est maintenant le même dans ce5d37c~
. Le deuxième diff montre que l'index et l'arbre de travail sont les mêmes. Le troisième diff montre que le seul changement par étapes consiste à déplacer le sous-module sub
vers un commit différent.
Commettre
git commit
Cela valide l'entrée du sous-module fixe.
Cette erreur peut signifier qu'un commit est manquant dans le sous-module. C'est-à-dire que le référentiel (A) a un sous-module (B). A veut charger B pour qu'il pointe vers un certain commit (dans B). Si ce commit est manquant, vous obtiendrez cette erreur. Une fois la cause possible: la référence au commit a été poussée dans A, mais le commit réel n'a pas été poussé de B. Donc je commencerais par là.
Moins probable, il y a un problème d'autorisations, et le commit ne peut pas être extrait (possible si vous utilisez git + ssh).
Assurez-vous que les chemins des sous-modules sont corrects .git/config et .gitmodules.
Une dernière chose à essayer-dans le répertoire des sous-modules: git reset HEAD --hard
Cause Possible
Cela peut se produire lorsque:
- les sous-modules ont été modifiés en place
- sous-module(s) commis, qui met à jour le hachage du sous-module pointé vers
- sous-module(s) pas poussé.
Par exemple, quelque chose comme ça est arrivé:
$ cd submodule
$ emacs my_source_file # edit some file(s)
$ git commit -am "Making some changes but will forget to push!"
Devrait avoir un sous-module poussé à ce stade.
$ cd .. # back to parent repository
$ git commit -am "updates to parent repository"
$ git push origin master
Par conséquent, les commits manquants n'ont pas pu être trouvés par l'utilisateur distant car ils sont toujours sur le disque local.
Solution
Informa la personne qui a modifié le sous-module pour pousser, c'est-à-dire
$ cd submodule
$ git push
Cela peut également se produire lorsque vous avez un sous-module pointant vers un référentiel qui a été rebasé et que le commit donné est "parti". Bien que la validation puisse toujours se trouver dans le référentiel distant, elle ne se trouve pas dans une branche. Si vous ne pouvez pas créer une nouvelle branche (par exemple, pas votre référentiel), vous devez mettre à jour le super projet pour pointer vers un nouveau commit. Vous pouvez également pousser l'une de vos copies des sous-modules ailleurs, puis mettre à jour le super-projet pour pointer vers ce référentiel à la place.
J'ai eu cette erreur quand je l'ai fait:
$ git submodule update --init --depth 1
Mais le commit du projet parent pointait vers un commit antérieur.
Suppression du dossier sous-module et exécution de
$ git submodule update --init
N'a pas résolu le problème. J'ai supprimé le repo et essayé à nouveau sans le drapeau de profondeur et cela a fonctionné.
Cette réponse est pour les utilisateurs de SourceTree avec une expérience limitée de terminal git.
Ouvrez le sous-module problématique depuis le projet Git (super-projet).
Fetch et assurez-vous que 'Fetch all tags' est coché.
Rebase tirez votre projet Git.
Cela résoudra le problème' la référence n'est pas un arbre ' 9 fois sur dix. Cette fois 1, Il ne sera pas, est un correctif de terminal comme décrit par la réponse supérieure.
L'historique de votre sous-module est conservé en toute sécurité dans le sous-module git de toute façon.
Alors, pourquoi ne pas simplement supprimer le sous-module et l'ajouter à nouveau?
Sinon, avez-vous essayé de modifier manuellement le HEAD
ou le refs/master/head
dans le sous-module .git
Juste pour être sûr, essayez de mettre à jour vos binaires git
.
GitHub pour Windows a la version git version 1.8.4.msysgit.0
qui dans mon cas était le problème. La mise à jour de la résoudre.
Dans mon cas, aucune des réponses ci-dessus ne résout le problème même si ce sont de bonnes réponses. Donc, je poste ma solution (dans mon cas, il y a deux clients git, client a et b):
-
Aller au répertoire du sous-module:
cd sub
-
Commander au maître:
git checkout master
-
Rebase en un code de validation que les deux clients peuvent voir
-
Retour au répertoire du parent:
S'Engager à maîtriser
Changer pour l'autre client do do
rebase
Encore une fois.Enfin, il fonctionne très bien maintenant! Peut-être perdre quelques commits mais cela fonctionne.
POUR INFO, n'essayez pas de supprimer votre sous-module, il restera
.git/modules
là et ne pourra plus readd ce sous-module, à moins d'un sous-module local réactif.
Pour synchroniser le dépôt git avec la tête du sous-module, au cas où c'est vraiment ce que vous voulez, j'ai trouvé que supprimer le sous-module puis le lire évite de bricoler avec l'historique. Malheureusement, la suppression d'un sous-module nécessite un piratage plutôt que d'être une seule commande git, mais faisable.
Étapes que j'ai suivies pour supprimer le sous-module, inspiré par https://gist.github.com/kyleturner/1563153 :
- exécuter git rm --mis en cache
- supprimer les lignes pertinentes du .fichier gitmodules.
- Supprimer la section pertinente de .git / config.
- supprimez les sous-modules non suivis.
- supprimer le répertoire .git / modules /
Encore une fois, cela peut être utile si tout ce que vous voulez est de pointer à nouveau vers la tête du sous-module, et vous n'avez pas compliqué les choses en ayant besoin de garder la copie locale du sous-module intacte. Il suppose que vous avez le sous-module "droit" comme son propre repo, où que soit l'origine de celui-ci, et vous voulez juste revenir à correctement y compris comme un sous-module.
Note: faites toujours une copie complète de votre projet avant de vous engager dans ce genre de manipulation ou toute commande git au-delà de simples commit ou push. Je conseillerais cela avec toutes les autres réponses, et en tant que Directive générale git.
Juste tombé sur ce problème, et aucune de ces solutions n'a fonctionné pour moi. Ce qui s'est avéré être la solution pour mon problème est en fait beaucoup plus simple: mettre à niveau Git. Le mien était 1.7.1, et après l'avoir mis à jour à 2.16.1 (dernier), le problème est parti sans laisser de trace! Je suppose que je le laisse ici, j'espère que ça aidera quelqu'un.