Erreur `` La référence n'est pas un arbre '' de la tête du sous-module Git

305

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'essaye de le récupérer dans un autre dépôt, j'obtiens:

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

Je sais ce que le chef de sous - module devrait être, est - il possible que je peux changer ce localement, sans pousser de la prise en pension qui ne se sont engager 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Je ne suis pas sûr d'être clair ... voici une situation similaire que j'ai trouvée.

Mauricio Scheffer
la source
11
"fatal: la référence n'est pas un arbre" en référence aux sous-modules semble généralement signifier que le commit du sous-module que le référentiel parent attend n'a pas encore été poussé, ou est foutu d'une autre manière. Pour nous, ce message d'erreur déroutant a été résolu en appuyant simplement sur un sous-module que quelqu'un avait oublié de pousser.
Chris Moschini
1
@ChrisMoschini - Je viens d'avoir ce problème, et c'était ma "solution", j'ai poussé et tiré le dépôt principal, mais j'ai oublié de pousser mon dernier commit sur le dépôt du sous-module. Merci!
Rotem
Peut-être que vous avez oublié de pousser les derniers commits de sous-module
Hafenkranich

Réponses:

378

En supposant que le référentiel du sous-module contient une validation que vous souhaitez utiliser (contrairement à la validation qui est référencée à partir de l'état actuel du super-projet), il existe deux façons de le faire.

La première nécessite que vous connaissiez déjà le commit du sous-module que vous souhaitez utiliser. Il fonctionne de «l'intérieur, de l'extérieur» en ajustant directement le sous-module puis en mettant à jour le super-projet. Le second fonctionne de «l'extérieur vers l'intérieur» en trouvant la validation du super-projet qui a modifié le sous-module, puis en réinitialisant l'index du super-projet pour faire référence à une autre validation de sous-module.

À l'envers

Si vous savez déjà que vous voulez engager le sous - module à l' utilisation, cdà la sous - module, consultez la vous vous engagez voulez, puis git addet git commitrevenir 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 effectué un commit de super-projet qui fait référence à un commit non publié dans le sous-module sub. D'une manière ou d'une autre, nous savons déjà que nous voulons que le sous-module soit validé 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Allez-y et vérifiez-le 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 un HEAD détaché dans le sous-module. Si vous voulez vous assurer que le sous-module utilise une branche, utilisez ensuite git checkout -b newbranch <commit>pour créer et extraire une branche lors de la validation ou extraire la branche que vous souhaitez (par exemple, une avec la validation souhaitée à la pointe).

Mettre à jour le Super-projet

Une extraction dans le sous-module se reflète dans le super-projet en tant que modification de l'arborescence 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 identiques. Le troisième diff montre que le seul changement par étapes consiste à déplacer le subsous - module vers un commit différent.

Commettre

git commit

Cela valide l'entrée de sous-module fixe.


Dehors dans

Si vous n'êtes pas sûr de la validation que vous devez utiliser à partir du sous-module, vous pouvez consulter l'historique du 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.

Retrouvez le Errant Commit 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 qu'il a mal tourné ce5d37c, nous allons donc restaurer le sous-module à partir de son parent ( ce5d37c~).

Alternativement, vous pouvez prendre la validation du sous-module à partir du texte du patch ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) et utiliser à la place le processus ci-dessus «dedans, dehors».

Commander dans le Super-projet

$ git checkout ce5d37c~ -- sub

Cela réinitialise l'entrée du sous-module pour subce qu'elle était lors de la validation 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 subc'est maintenant la même chose 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 subsous - module vers un autre commit.

Commettre

git commit

Cela valide l'entrée de sous-module fixe.

Chris Johnsen
la source
Dans l'approche «À l'extérieur, à l'intérieur», pourriez-vous expliquer pourquoi «il semble que tout s'est mal passé dans ce5d37c? Quels doigts celui-là comme le mauvais commettent?
Garrett Albright
5
@ Garrett: L'hypothèse est e47c0aune validation qui n'existe pas dans le référentiel local sub, mais le super-projet subpointe vers cette validation. Cela peut se produire parce que quelqu'un d'autre a créé e47c0adans sa copie de sub, mis à jour son super-projet pour pointer vers cette validation et a poussé le super-projet sans pousser e47c0avers le référentiel central / partagé pour sub. Lorsque nous tirons du super-projet central / partagé, nous obtenons un commit qui pointe subvers e47c0a, mais nous ne pouvons pas «voir» ce commit. ce5d37cest suspect car, sur la base du diff, il a introduit e47c0a.
Chris Johnsen
Il est encore assez vague où se trouve le hachage spécifique de la subconservation dans le référentiel parent qui l'a comme sous-module, et s'il peut être manipulé directement vers la tête actuelle de subdirectement, sans s'appuyer sur un état plus ancien du parent repo, qui peut ne pas toujours aider.
matanster
187

essaye ça:

git submodule sync
git submodule update
Lonre Wang
la source
2
Pas pour moi, malheureusement, l'un de nos sous-modules a été ciblé par le référentiel git principal avec une commande d'ajout, ayant maintenant du mal à l'annuler
Daniel
9
A aussi fonctionné pour moi. J'adorerais savoir pourquoi.
BenBtg
12
Il s'avère que faire un git submodule syncest nécessaire dans les scénarios où l'URL de la télécommande pour un sous-module donné a changé. Dans notre cas, nous avions ajouté notre sous-module à partir d'un dépôt public, puis changé l'URL en un fork privé - et nous nous sommes mis dans ce cornichon particulier.
Samscam
Par exemple: j'avais un dépôt (A) mis en place avec un sous-module pointant vers mon dépôt github (B). J'ai créé une branche dans le référentiel A parce que je voulais pointer B vers le référentiel github de quelqu'un d'autre. Après avoir lutté un peu avec cela et engagé la branche, j'ai remis mon repo A en maître et j'ai eu ce problème avec le repo B. La solution de @Lonre Wang l'a corrigé.
fbicknel
2
En supposant que personne n'a VRAIMENT foiré (auquel cas vous auriez besoin d'une excellente réponse de Chris Johnsen) la réponse de Lonre Wang devrait résoudre le problème, ... À MOINS que vos sous-modules aient leurs propres sous-modules (et le problème est à l'intérieur d'un sous-module). Dans ce cas, vous devez cd dans le sous-module qui a le sous-module avec le problème et exécuter les commandes ci-dessus. Notez que la mise à jour a une option --recursive (mise à jour du sous-module git --recursive), mais pas la synchronisation; vous devez vraiment exécuter manuellement 'git submodule sync' à l'intérieur du sous-module qui a le sous (sous) module problématique. C'était mon problème;).
Carlo Wood
16

Cette erreur peut signifier qu'un commit est manquant dans le sous-module. Autrement dit, le référentiel (A) a un sous-module (B). A veut charger B pour qu'il pointe vers un certain commit (en B). Si cette validation est manquante, vous obtiendrez cette erreur. Autrefois cause possible: la référence au commit a été poussée dans A, mais le commit réel n'a pas été poussé depuis B. Donc je commencerais par là.

Moins probablement, il y a un problème d'autorisations et la validation ne peut pas être extraite (possible si vous utilisez git + ssh).

Assurez-vous que les chemins des sous-modules semblent corrects dans .git / config et .gitmodules.

Une dernière chose à essayer - dans le répertoire du sous-module: git reset HEAD --hard

Daniel Tsadok
la source
3
J'ai déjà expliqué que dans la question ... la question elle-même était de savoir comment le résoudre. Et il a déjà été répondu avec succès il y a près de deux ans ... Les autorisations n'ont rien à voir avec cela.
Mauricio Scheffer
1
Vous l'avez dit, vous ne l'avez certainement pas expliqué.
Daniel Tsadok
Mon point est que cette réponse n'ajoute aucune information précieuse, je la supprimerais.
Mauricio Scheffer
4
le "git reset HEAD --hard" m'a aussi aidé ... rien d'autre n'a fonctionné. J'ai aussi essayé les solutions précédentes, pas de dés. Merci!
Virgil
1
Chaque fil est son propre petit monde en ligne. Ce que vous dites vous représente - vous ne pouvez pas vous attendre à ce que les gens étudient votre histoire personnelle pour essayer de cadrer vos commentaires dans un contexte qui vous accorde le respect que vous désirez. Soyez gentil, respectueux et vous n'aurez pas besoin de demander aux gens de comprendre vos bizarreries personnelles. Si vous pouvez lire votre commentaire dans un contexte neutre, comme le ferait un étranger, vous comprendrez ma critique.
Stabledog
10

Cause possible

Cela peut se produire lorsque:

  1. Les sous-modules ont été modifiés sur place
  2. Sous- module (s) engagé (s), qui met à jour le hachage du sous-module pointé vers
  3. Sous-module (s) non poussé (s) .

par exemple quelque chose comme ça s'est produit:

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

Devrait avoir poussé le sous-module à ce stade.

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

Par conséquent, les validations manquantes n'ont pas pu être trouvées par l'utilisateur distant car elles se trouvent toujours sur le disque local.

Solution

Informer la personne qui a modifié le sous-module pour pousser, c'est-à-dire

$ cd submodule
$ git push
chriskelly
la source
6

J'ai eu cette erreur quand j'ai fait:

$ git submodule update --init --depth 1

mais la validation dans le projet parent pointait vers une validation antérieure.

Suppression du dossier du sous-module et exécution:

$ git submodule update --init

n'a PAS résolu le problème. J'ai supprimé le dépôt et réessayé sans l'indicateur de profondeur et cela a fonctionné.

Cette erreur se produit dans Ubuntu 16.04 git 2.7.4, mais pas sur Ubuntu 18.04 git 2.17, TODO trouve la correction ou la version de correction exacte.

Platon
la source
mon équipe a depuis abandonné les sous-modules dans notre code beaucoup trop de tracas lol
Platon
1
quelle était votre alternative?
nuzzolilo
@nuzzolilo nous avons ajouté username/repo#shaà package.json, une option beaucoup plus flexible est d'organiser votre système avec un ensemble de conteneurs docker
Platon
3
C'est tellement ennuyeux. --depth=1économise tellement de bande passante quand je n'ai pas besoin de l'historique du dépôt. Si quelqu'un trouve ou sait pourquoi cela se produit, j'aimerais savoir.
i336_
@ i336_ Bien que je ne puisse pas expliquer pourquoi, j'ai écrit une aide cmake qui aide à atténuer le problème ici: github.com/LMMS/lmms/blob/… . Il utilise une deinitapproche qui résout le problème la plupart du temps. Lorsqu'il est intégré à un système de génération, l'utilisateur final peut simplement laisser le système de génération récupérer les sous-modules et abandonner recursivecomplètement la commande cassée . Il y a encore des scénarios où cela se casse, comme le sous-module qui a effectué une poussée de force et annulé complètement le commit.
tresf
5

Cela peut également se produire lorsque vous avez un sous-module pointant vers un référentiel qui a été rebasé et que la validation donnée a «disparu». Bien que la validation puisse toujours être dans le référentiel distant, elle n'est pas dans une branche. Si vous ne pouvez pas créer une nouvelle branche (par exemple pas votre référentiel), vous êtes obligé de mettre à jour le super projet pour pointer vers un nouveau commit. Vous pouvez également pousser une de vos copies des sous-modules ailleurs, puis mettre à jour le super-projet pour pointer vers ce référentiel à la place.

pasamio
la source
5

Votre agence n'est peut-être pas à jour, une solution simple mais essayez git fetch

kittycatbytes
la source
2

Cette réponse est destinée aux utilisateurs de SourceTree avec une expérience limitée de git de terminal.

Ouvrez le sous-module problématique depuis le projet Git (super-projet).

Récupérez et assurez-vous que «Récupérer toutes les balises» 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 1 fois, ce n'est pas le cas, c'est un correctif de terminal comme décrit par la réponse du haut.

ericTbear
la source
1

Votre historique de sous-module est de toute façon préservé dans le git de sous-module.

Alors, pourquoi ne pas simplement supprimer le sous-module et l'ajouter à nouveau?

Sinon, avez-vous essayé de modifier manuellement le HEADou le refs/master/headdans le sous-module.git

Lakshman Prasad
la source
1
Cela ne fonctionnera pas, car quelque part il y a une référence à 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 qui est uniquement dans le dépôt local ailleurs, mais non publié
Mauricio Scheffer
1

Juste pour être sûr, essayez de mettre à jour vos gitbinaires.

GitHub pour Windows a la version git version 1.8.4.msysgit.0qui dans mon cas était le problème. La mise à jour l'a résolu.

Gman
la source
1

Dans mon cas, aucune des réponses ci-dessus ne résout le problème même si ce sont de bonnes réponses. Je poste donc ma solution (dans mon cas il y a deux clients git, le client A et B):

  1. allez dans le répertoire du sous-module:

    cd sub
    
  2. caisse à maîtriser:

    git checkout master
    
  3. rebaser en un code de validation que les deux clients peuvent voir

  4. revenir au répertoire des parents:

  5. s'engager à maîtriser

  6. passer à l'autre client ,rebaserefaire.

  7. enfin ça marche bien maintenant! Peut-être perdre quelques commits mais ça marche.

  8. Pour info, n'essayez pas de supprimer votre sous-module, il y restera .git/moduleset ne pourra plus relire ce sous-module, sauf si réactif local.

kimimaro
la source
1

Pour synchroniser le git repo avec la tête du sous-module, au cas où c'est vraiment ce que vous voulez, j'ai trouvé qu'en supprimant le sous-module puis en le relisant, vous évitiez de bricoler l'historique. Malheureusement, la suppression d'un sous-module nécessite un piratage plutôt qu'une simple commande git, mais faisable.

Étapes que j'ai suivies pour supprimer le sous-module, inspirées de https://gist.github.com/kyleturner/1563153 :

  1. Exécutez git rm --cached
  2. Supprimez les lignes pertinentes du fichier .gitmodules.
  3. Supprimez la section appropriée de .git / config.
  4. Supprimez les fichiers de sous-module désormais non suivis.
  5. Supprimez le répertoire .git / modules /

Encore une fois, cela peut être utile si tout ce que vous voulez est de pointer à nouveau 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 "bon" sous-module comme son propre référentiel, quelle que soit l'origine de celui-ci, et que vous souhaitiez simplement l'inclure correctement en tant que sous-module.

Remarque: faites toujours une copie complète de votre projet avant de vous lancer dans ce type de manipulation ou toute commande git au-delà du simple commit ou push. Je conseillerais cela avec toutes les autres réponses également, et comme une ligne directrice générale.

matanster
la source
1

Je suis 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 à mon problème est en fait beaucoup plus simple: mettre à niveau Git. Le mien était 1.7.1, et après l'avoir mis à niveau vers 2.16.1 (le plus récent), le problème a disparu sans laisser de trace! Je suppose que je le laisse ici, j'espère que ça aide quelqu'un.

An Phan
la source