Mise à jour du sous-module Git

242

Je ne sais pas exactement ce que cela signifie (à partir de la documentation de mise à jour du sous-module Git ):

... fera détacher les sous-modules HEAD, sauf si --rebaseou --mergeest spécifié ...

Comment change --rebase/ --mergechange les choses?

Mon cas d'utilisation principal est d'avoir un tas de référentiels centraux, que j'intégrerai via des sous-modules dans d'autres référentiels. Je voudrais pouvoir améliorer ces référentiels centraux, soit directement dans leur emplacement d'origine, soit à partir de leurs référentiels d'intégration (ceux qui les utilisent via le sous-module).

  • À partir de ces sous-modules, puis-je créer des branches / modifications et utiliser push / pull comme je le ferais dans les référentiels habituels, ou y a-t-il des choses à faire attention?
  • Comment pourrais-je faire avancer la validation référencée du sous-module de say (tagged) 1.0 à 1.1 (même si la tête du référentiel d'origine est déjà à 2.0), ou choisir quelle validation de la branche est utilisée?
bleu profond
la source
Sur le sujet de la "tête détachée", voir aussi stackoverflow.com/questions/964876/head-and-orighead-in-git et stackoverflow.com/questions/237408/… pour un exemple pratique (pas lié au sous-module, mais quand même )
VonC
"vous ne pouvez pas modifier le contenu du sous-module depuis le projet principal": oui, vrai. Et j'ai édité ma réponse pour faire la lumière sur cette contradiction apparente (sous-module non modifiable, que vous pouvez toujours modifier à partir du
référentiel du

Réponses:

304

Cette page GitPro résume bien les conséquences d'une mise à jour du sous-module git

Lorsque vous exécutez git submodule update, il extrait la version spécifique du projet, mais pas dans une branche. C'est ce qu'on appelle avoir une tête détachée - cela signifie que le fichier HEAD pointe directement vers une validation, pas vers une référence symbolique.
Le problème est que vous ne voulez généralement pas travailler dans un environnement de tête détachée, car il est facile de perdre les modifications .
Si vous effectuez une mise à jour initiale du sous-module, validez dans ce répertoire de sous-module sans créer de branche dans laquelle travailler, puis réexécutez la mise à jour du sous-module git à partir du superprojet sans vous engager entre-temps, Git écrasera vos modifications sans vous le dire. Techniquement, vous ne perdrez pas le travail, mais vous n'aurez pas de branche pointant dessus, il sera donc quelque peu difficile à récupérer.


Remarque mars 2013:

Comme mentionné dans " git submodule tracking latest ", un sous-module maintenant (git1.8.2) peut suivre une branche.

# add submodule to track master branch
git submodule add -b master [URL to Git repo];

# update your submodule
git submodule update --remote 
# or (with rebase)
git submodule update --rebase --remote

Voir " git submodule update --remotevsgit pull ".

La réponse de MindTooth illustre une mise à jour manuelle (sans configuration locale):

git submodule -q foreach git pull -q origin master

Dans les deux cas, cela changera les références des sous-modules (le gitlink , une entrée spéciale dans l'index du référentiel parent ), et vous devrez ajouter, valider et pousser lesdites références depuis le référentiel principal.
La prochaine fois que vous clonerez ce référentiel parent, il remplira les sous-modules pour refléter ces nouvelles références SHA1.

Le reste de cette réponse détaille la fonctionnalité de sous-module classique (référence à un commit fixe , qui est le point derrière la notion de sous-module).


Pour éviter ce problème, créez une branche lorsque vous travaillez dans un répertoire de sous-module avec git checkout -b work ou quelque chose d'équivalent. Lorsque vous effectuez la mise à jour du sous-module une deuxième fois, il reviendra toujours à votre travail, mais au moins vous avez un pointeur sur lequel revenir.

Changer de branche avec des sous-modules peut également être délicat. Si vous créez une nouvelle branche, y ajoutez un sous-module, puis revenez à une branche sans ce sous-module, vous avez toujours le répertoire du sous-module en tant que répertoire non suivi:


Donc, pour répondre à vos questions:

puis-je créer des branches / modifications et utiliser push / pull comme je le ferais dans les dépôts réguliers, ou y a-t-il des choses à faire attention?

Vous pouvez créer une branche et pousser les modifications.

AVERTISSEMENT (à partir du didacticiel de sous-module Git ): publiez (poussez) toujours la modification de sous-module avant de publier (poussez) la modification dans le superprojet qui la référence. Si vous oubliez de publier la modification du sous-module, les autres ne pourront pas cloner le référentiel.

comment pourrais-je faire avancer le commit référencé du sous-module de say (tagged) 1.0 à 1.1 (même si la tête du dépôt d'origine est déjà à 2.0)

La page " Comprendre les sous-modules " peut vous aider

Les sous-modules Git sont implémentés à l'aide de deux parties mobiles:

  • le .gitmodulesfichier et
  • un type d'arbre particulier.

Ensemble, ils triangulent une révision spécifique d'un référentiel spécifique qui est extrait dans un emplacement spécifique de votre projet.


Depuis la page du sous-module git

vous ne pouvez pas modifier le contenu du sous-module depuis le projet principal

100% correct: vous ne pouvez pas modifier un sous-module, ne vous référez qu'à l'un de ses commits.

C'est pourquoi, lorsque vous modifiez un sous-module à partir du projet principal, vous:

  • besoin de s'engager et de pousser dans le sous-module (vers le module en amont), et
  • remontez ensuite dans votre projet principal, et recommencez (pour que ce projet principal fasse référence au nouveau commit de sous-module que vous venez de créer et de pousser)

Un sous-module vous permet d'avoir une approche de développement basée sur les composants , où le projet principal ne fait référence qu'à des validations spécifiques d'autres composants (ici "d'autres référentiels Git déclarés comme sous-modules").

Un sous-module est un marqueur (commit) vers un autre référentiel Git qui n'est pas lié par le cycle de développement principal du projet: il (l '"autre" dépôt Git) peut évoluer indépendamment.
Il appartient au projet principal de choisir dans cet autre référentiel tout engagement dont il a besoin.

Cependant, si vous souhaitez, par commodité , modifier l'un de ces sous-modules directement à partir de votre projet principal, Git vous permet de le faire, à condition de publier d' abord ces modifications de sous-module dans son référentiel Git d'origine, puis de valider votre projet principal en vous référant à une nouvelle version dudit sous-module.

Mais l'idée principale reste: référencer des composants spécifiques qui:

  • ont leur propre cycle de vie
  • ont leur propre jeu de balises
  • avoir leur propre développement

La liste des validations spécifiques à laquelle vous vous référez dans votre projet principal définit votre configuration (c'est de cela dont parle la gestion de la configuration , englobant un simple système de contrôle de version )

Si un composant pouvait vraiment être développé en même temps que votre projet principal (car toute modification sur le projet principal impliquerait de modifier le sous-répertoire, et vice-versa), alors ce ne serait plus un "sous-module", mais un fusion de sous-arborescence (également présentée dans la question Transfert de la base de code héritée des cv vers le référentiel distribué ), reliant ensemble l'historique des deux référentiels Git.

Est-ce que cela aide à comprendre la vraie nature des sous-modules Git?

VonC
la source
77
Sensationnel. Cette longue explication pour quelque chose qui est principalement aussi simple devrait suffire à effrayer tout nouvel arrivant à s'en tenir à leur svn: externals. ;-)
conny
2
@conny: mais, comme je le détaille dans " Pourquoi les sous-modules git sont-ils incompatibles avec les externes svn? ", les sous-modules sont fondamentalement différents et ne sont pas compatibles avec svn:externals.
VonC
1
Désolé, pour répondre à ma propre question, je rassemble des cd'ing dans le sous-module et git checkout un sha, ou git pull / fetch fera l'affaire. Valider ensuite la mise à jour dans le référentiel local.
Henrik
2
@hced: Vous pouvez également toucher tous les sous-modules en même temps en utilisantgit submodule foreach
Dav Clark
1
.. toujours pas compris. Y a-t-il une explication plus facile sur le Web quelque part?
eugene
135

Pour mettre à jour chaque sous-module, vous pouvez invoquer la commande suivante (à la racine du référentiel):

git submodule -q foreach git pull -q origin master

Vous pouvez supprimer l' option -q pour suivre l'ensemble du processus.

MindTooth
la source
15
Si vous exécutez simplement à git submodule update --init --recursivepartir de la racine, il les récupérera tous de manière récursive et les initialisera s'ils ne le sont pas déjà.
Sam Soffes
10
@SamSoffes Cela sert un but complètement différent. La mise à jour des sous-modules vérifiera les sous-modules lors de la validation vers laquelle ils pointent actuellement (pas nécessairement la dernière validation). La solution de la réponse ci-dessus met à jour la validation de chaque sous-module vers le dernier HEAD d'origine / maître.
indragie
7
Ma nouvelle méthode:git submodule update --rebase --remote
MindTooth
19

Pour traiter l' option --rebasevs --merge:

Supposons que vous ayez un super référentiel A et un sous-module B et que vous vouliez travailler dans le sous-module B. Vous avez fait vos devoirs et vous savez qu'après avoir appelé

git submodule update

vous êtes dans un état sans TÊTE, il est donc difficile de revenir sur tous les engagements que vous effectuez à ce stade. Vous avez donc commencé à travailler sur une nouvelle branche dans le sous-module B

cd B
git checkout -b bestIdeaForBEver
<do work>

Pendant ce temps, quelqu'un d'autre dans le projet A a décidé que la dernière et la meilleure version de B est vraiment ce que A mérite. Par habitude, vous fusionnez les modifications les plus récentes et mettez à jour vos sous-modules.

<in A>
git merge develop
git submodule update

Oh non! Vous êtes à nouveau dans un état sans tête, probablement parce que B pointe maintenant vers le SHA associé au nouveau conseil de B, ou un autre commit. Si seulement vous aviez:

git merge develop
git submodule update --rebase

Fast-forwarded bestIdeaForBEver to b798edfdsf1191f8b140ea325685c4da19a9d437.
Submodule path 'B': rebased into 'b798ecsdf71191f8b140ea325685c4da19a9d437'

Maintenant que la meilleure idée de B a été rebasée sur le nouveau commit, et plus important encore, vous êtes toujours sur votre branche de développement pour B, pas dans un état sans tête!

(Le --mergefusionnera les modifications de beforeUpdateSHA à afterUpdateSHA dans votre branche de travail, au lieu de rebaser vos modifications sur afterUpdateSHA.)

robinspb
la source
7

Git 1.8.2 propose une nouvelle option --remote, qui activera exactement ce comportement. Fonctionnement

git submodule update --rebase --remote

récupérera les dernières modifications en amont dans chaque sous-module, les rebasera et vérifiera la dernière révision du sous-module. Comme le dit la documentation :

--éloigné

Cette option n'est valable que pour la commande update. Au lieu d'utiliser le SHA-1 enregistré du superprojet pour mettre à jour le sous-module, utilisez l'état de la branche de suivi à distance du sous-module.

Cela revient à exécuter git pulldans chaque sous-module, ce qui est généralement exactement ce que vous voulez.

(Ceci a été copié de cette réponse .)

Iulian Onofrei
la source
Si vous décidez de répondre à une question plus ancienne qui a des réponses bien établies et correctes, l'ajout d'une nouvelle réponse en fin de journée peut ne pas vous valoir de crédit. Si vous avez de nouvelles informations distinctives, ou si vous êtes convaincu que les autres réponses sont toutes fausses, ajoutez certainement une nouvelle réponse, mais `` encore une autre réponse '' donnant les mêmes informations de base longtemps après que la question a été posée est généralement gagnée '' t vous gagner beaucoup de crédit. Il n'y a aucune explication de ce que cela fait - pas même un lien vers une documentation externe (ce qui ne serait pas suffisant).
Jonathan Leffler
2
Ce n'est pas "encore une autre réponse", car AUCUNE autre réponse n'a cette commande (prouve-moi le contraire). Les autres réponses n'ont pas fonctionné pour moi, ce commentaire l'a fait, j'ai donc décidé de le poster comme une réponse tout en donnant du crédit au propriétaire d'origine. Pensez donc à supprimer votre downvote.
Iulian Onofrei
Il y a un commentaire de MindTooth de 2015 disant que c'est ce qu'ils font maintenant. Vous ne donnez aucune explication de ce que cela fait (bien que vous mentionniez MindTooth, mais il n'y a aucune explication réelle de ce que vous entendez par cela - l'intégration d'URL, comme dans ce commentaire, aiderait). Vous ne dites pas pourquoi c'est une bonne idée. Vous ne faites aucune mise en garde. À mon avis, ce n'est pas une réponse utile car elle soulève plus de questions qu'elle n'en résout.
Jonathan Leffler
1
Par cela, je voulais dire que cela fonctionne au lieu de ne pas fonctionner. Croyez-moi, si plus de gens voyaient cette réponse, ils seraient contents, car cela fonctionne . Pour des choses comme ça, la plupart des gens veulent juste connaître la commande qui met à jour un sous-module git, pas comment il est implémenté.
Iulian Onofrei
J'ai édité la réponse pour vous prouver le contraire, aussi, stackoverflow.com/questions/1979167/git-submodule-update/… !!!
Iulian Onofrei