Il semble que deux scénarios différents soient mélangés dans cette discussion :
Scénario 1
En utilisant les pointeurs de mon dépôt parent vers les sous-modules, je veux vérifier le commit dans chaque sous-module vers lequel le dépôt parent pointe, éventuellement après avoir d'abord itéré à travers tous les sous-modules et les avoir mis à jour/tirés à distance.
Cela se fait, comme on l'a souligné, avec
git submodule foreach git pull origin BRANCH
git submodule update
Scénario 2, qui, je pense, est le but du PO.
De nouvelles choses se sont produites dans un ou plusieurs sous-modules, et je veux 1) récupérer ces changements et 2) mettre à jour le dépôt parent pour qu'il pointe vers le commit HEAD (le plus récent) de ce/ces sous-modules.
Pour ce faire, il faudrait
git submodule foreach git pull origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git push origin BRANCH
Pas très pratique, car il faudrait coder en dur n chemins vers les n submodules dans par exemple un script pour mettre à jour les pointeurs de commit du dépôt parent.
Il serait intéressant d'avoir une itération automatisée à travers chaque sous-module, en mettant à jour le pointeur du dépôt parent (à l'aide de git add
) pour pointer vers la tête du (des) sous-module(s).
Pour cela, j'ai fait ce petit Bash script :
git-update-submodules.sh
#!/bin/bash
APP_PATH=$1
shift
if [ -z $APP_PATH ]; then
echo "Missing 1st argument: should be path to folder of a git repo";
exit 1;
fi
BRANCH=$1
shift
if [ -z $BRANCH ]; then
echo "Missing 2nd argument (branch name)";
exit 1;
fi
echo "Working in: $APP_PATH"
cd $APP_PATH
git checkout $BRANCH && git pull --ff origin $BRANCH
git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git push origin $BRANCH
Pour le lancer, exécutez
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Élaboration
Tout d'abord, je suppose que la branche avec le nom $BRANCH (deuxième argument) existe dans tous les dépôts. N'hésitez pas à rendre cela encore plus complexe.
Les deux premières sections consistent à vérifier que les arguments sont présents. Ensuite, je tire les derniers éléments du dépôt parent (je préfère utiliser --ff (avance rapide) quand je ne fais que des tirages. J'ai désactivé rebase, BTW).
git checkout $BRANCH && git pull --ff origin $BRANCH
Ensuite, il peut être nécessaire d'initialiser certains sous-modules, si de nouveaux sous-modules ont été ajoutés ou ne sont pas encore initialisés :
git submodule sync
git submodule init
git submodule update
Ensuite, je mets à jour et retire tous les sous-modules :
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
Remarquez certaines choses : Tout d'abord, j'enchaîne quelques commandes Git en utilisant &&
- ce qui signifie que la commande précédente doit s'exécuter sans erreur.
Après un éventuel pull réussi (si de nouveaux éléments ont été trouvés sur le distant), je fais un push pour m'assurer qu'un éventuel merge-commit n'est pas laissé sur le client. Encore une fois, cela n'arrive que si une traction a effectivement apporté de nouvelles choses.
Enfin, la finale || true
est de s'assurer que script continue sur les erreurs. Pour que cela fonctionne, tout ce qui se trouve dans l'itération doit être enveloppé dans les guillemets et les commandes Git sont enveloppées dans les parenthèses (préséance des opérateurs).
Ma partie préférée :
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
Itérer tous les submodules - avec --quiet
ce qui supprime le message "Entering MODULE_PATH". Utilisation de 'echo $path'
(doit être entre guillemets), le chemin vers le sous-module est écrit en sortie.
Cette liste de chemins relatifs de sous-modules est capturée dans un tableau ( $(...)
) - enfin itérer ceci et faire git add $i
pour mettre à jour le référentiel parent.
Enfin, un commit avec un message expliquant que le référentiel parent a été mis à jour. Ce commit sera ignoré par défaut, si rien n'a été fait. Poussez-le vers l'origine, et vous avez terminé.
J'ai un script qui exécute cela dans un Jenkins qui s'enchaîne à un déploiement automatique programmé par la suite, et cela fonctionne comme un charme.
J'espère que cela pourra être utile à quelqu'un.
8 votes
La réponse de David Z. semble être la meilleure façon de procéder - maintenant que Git a intégré la fonctionnalité dont vous avez besoin via l'option
--remote
Peut-être serait-il utile de marquer cette option comme étant la réponse acceptée plutôt que l'approche "à la main" de la réponse de Jason ?3 votes
Je suis tout à fait d'accord avec @MarkAmery. Bien que Jason ait donné une solution fonctionnelle, ce n'est pas la façon prévue de le faire, car elle laisse le pointeur de commit du sous-module au mauvais identifiant de commit. Le nouveau
--remote
est définitivement une meilleure solution à ce stade, et puisque cette question a été liée à un Gist Github sur les submodules, je pense qu'il serait préférable pour les lecteurs entrants de voir la nouvelle réponse.0 votes
Belle touche avec le
hunter2
mot de passe :o)