Un moyen facile de tirer le dernier de tous les sous-modules git

Nous utilisons des sous-modules git pour gérer quelques grands projets qui ont des dépendances sur de nombreuses autres bibliothèques que nous avons développées. Chaque bibliothèque est un référentiel distinct introduit dans le projet dépendant en tant que sous-module. Au cours du développement, nous voulons souvent récupérer la dernière version de chaque sous-module dépendant.

Est-ce que git a une commande intégrée pour faire cela? Si non, que diriez-vous d’un fichier de commandes Windows ou similaire qui peut le faire?

Pour git 1.8.2 ou supérieur, l’option --remote été ajoutée pour permettre la mise à jour des dernières astuces des twigs distantes:

 git submodule update --recursive --remote 

Cela a l’avantage supplémentaire de respecter toutes les twigs “non par défaut” spécifiées dans les .gitmodules ou .git/config (si vous en avez, la valeur par défaut est origine / master, auquel cas certaines des autres réponses fonctionneraient comme bien).

Pour git 1.7.3 ou supérieur, vous pouvez utiliser (mais ce qui suit concerne les mises à jour qui s’appliquent toujours):

 git submodule update --recursive 

ou:

 git pull --recurse-submodules 

Si vous voulez que vos sous-modules se connectent aux dernières commandes de ce que le repo pointe vers.

Note: Si c’est la première fois que vous achetez un repository, vous devez d’abord utiliser --init :

 git submodule update --init --recursive 

Pour les anciens, git 1.6.1 ou supérieur, vous pouvez utiliser quelque chose de similaire à (modifié pour convenir):

 git submodule foreach git pull origin master 

Voir git-submodule (1) pour plus de détails

Si vous devez extraire des éléments de sous-modules dans vos repositorys de sous-modules, utilisez

 git pull --recurse-submodules 

une caractéristique git d’abord apprise en 1.7.3.

Mais cela ne vérifiera pas les commits appropriés (ceux vers lesquels votre référentiel principal pointe) dans les sous-modules

Pour vérifier les commits corrects dans vos sous-modules, vous devez les mettre à jour après avoir utilisé

 git submodule update --recursive --remote 

Note: Cela date de 2009 et a peut-être été bon, mais il existe de meilleures options maintenant.

Nous l’utilisons C’est ce qu’on appelle git-pup :

 #!/bin/bash # Exists to fully update the git repo that you are sitting in... git pull && git submodule init && git submodule update && git submodule status 

Placez-le simplement dans un répertoire bin approprié (/ usr / local / bin). Si sous Windows, vous devrez peut-être modifier la syntaxe pour la faire fonctionner 🙂

Mettre à jour:

En réponse au commentaire de l’auteur d’origine sur l’insertion de tous les HEAD de tous les sous-modules, c’est une bonne question.

Je suis presque sûr que git n’a pas de commande pour cela en interne. Pour ce faire, vous devez identifier ce que HEAD est réellement pour un sous-module. Cela pourrait être aussi simple que de dire que master est la twig la plus à jour, etc.

Ensuite, créez un script simple qui effectue les opérations suivantes:

  1. vérifier le git submodule status pour les référentiels “modifiés”. Le premier caractère des lignes de sortie l’indique. Si un sous-repo est modifié, vous ne pouvez PAS vouloir continuer.
  2. pour chaque repo répertorié, cd dans son répertoire et lancez git checkout master && git pull . Vérifiez les erreurs.
  3. À la fin, je vous suggère d’imprimer un affichage à l’utilisateur pour indiquer l’état actuel des sous-modules – peut-être les inviter à append tout et valider?

J’aimerais mentionner que ce style n’est pas vraiment ce à quoi les sous-modules git ont été conçus. En règle générale, vous voulez dire “LibraryX” est à la version “2.32” et le restra jusqu’à ce que je lui dise de “mettre à jour”.

C’est en quelque sorte ce que vous faites avec le script décrit, mais de manière plus automatique. Des soins sont nécessaires!

Mise à jour 2:

Si vous êtes sur une plate-forme Windows, vous pouvez envisager d’utiliser Python pour implémenter le script car il est très performant dans ces domaines. Si vous êtes sur unix / linux, alors je suggère simplement un script bash.

Besoin de clarifications? Il suffit de poster un commentaire.

Sur init exécutant la commande suivante:

 git submodule update --init --recursive 

à partir du répertoire repo git, fonctionne le mieux pour moi.

Cela va tirer tous les derniers sous-modules y compris.

Expliqué

 git - the base command to perform any git command submodule - Inspects, updates and manages submodules. update - Update the registered submodules to match what the superproject expects by cloning missing submodules and updating the working tree of the submodules. The "updating" can be done in several ways depending on command line options and the value of submodule..update configuration variable. --init without the explicit init step if you do not intend to customize any submodule locations. --recursive is specified, this command will recurse into the registered submodules, and update any nested submodules within. 

Après cela, vous pouvez simplement exécuter:

 git submodule update --recursive 

à partir du répertoire repo git, fonctionne le mieux pour moi.

Cela va tirer tous les derniers sous-modules y compris.

Expliqué

 git - the base command to perform any git command submodule - Inspects, updates and manages submodules. update - Update the registered submodules to match what the superproject expects by cloning missing submodules and updating the working tree of the submodules. The "updating" can be done in several ways depending on command line options and the value of submodule..update configuration variable. any submodule locations. --recursive is specified, this command will recurse into the registered submodules, and update any nested submodules within. 

Henrik est sur la bonne voie. La commande ‘foreach’ peut exécuter n’importe quel script shell arbitraire. Deux options pour tirer le dernier peut être,

 git submodule foreach git pull origin master 

et,

 git submodule foreach /path/to/some/cool/script.sh 

Cela va parcourir tous les sous-modules initialisés et exécuter les commandes données.

Ce qui suit a fonctionné pour moi sur Windows.

 git submodule init git submodule update 

Modifier :

Dans les commentaires a été souligné (par philfreo ) que la dernière version est requirejse. S’il existe des sous-modules nesteds devant être dans leur dernière version:

 git submodule foreach --recursive git pull 

—– Commentaire obsolète ci-dessous —–

N’est-ce pas la manière officielle de le faire?

 git submodule update --init 

Je l’utilise à chaque fois. Pas de problèmes jusqu’ici.

Modifier:

Je viens de découvrir que vous pouvez utiliser:

 git submodule foreach --recursive git submodule update --init 

Ce qui tirera également récursivement tous les sous-modules, à savoir les dépendances.

Comme il se peut que la twig par défaut de vos sous-modules ne soit pas master , voici comment j’automatise les mises à niveau complètes des sous-modules Git:

 git submodule init git submodule update git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx' 

Première fois

Sous-module Clone et Init

 git clone [email protected]:speedovation/kiwi-resources.git resources git submodule init 

Du repos

Au cours du développement, il suffit de tirer et de mettre à jour le sous-module

 git pull --recurse-submodules && git submodule update --recursive 

Mise à jour du sous-module Git pour la dernière validation à l’origine

 git submodule foreach git pull origin master 

Manière préférée devrait être ci-dessous

 git submodule update --remote --merge 

note: les deux dernières commandes ont le même comportement

Je ne sais pas depuis quelle version de git cela fonctionne, mais c’est ce que vous recherchez:

 git submodule update --recursive 

Je l’utilise avec git pull pour mettre à jour le repository racine aussi:

 git pull && git submodule update --recursive 

Regardez http://lists.zerezo.com/git/msg674976.html qui introduit un paramètre –track

Git pour Windows 2.6.3 :

git submodule update --rebase --remote

Je l’ai fait en adaptant la réponse de gahooa ci – dessus :

Intégrez-le avec un git [alias]

Si votre projet parent a quelque chose comme ça dans les .gitmodules :

 [submodule "opt/submodules/solarized"] path = opt/submodules/solarized url = [email protected]:altercation/solarized.git [submodule "opt/submodules/intellij-colors-solarized"] path = opt/submodules/intellij-colors-solarized url = [email protected]:jkaving/intellij-colors-solarized.git 

Ajoutez quelque chose comme ceci dans votre .gitconfig

 [alias] updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" " 

Ensuite, pour mettre à jour vos sous-modules, exécutez:

 git updatesubs 

J’en ai un exemple dans mon repo de configuration de l’environnement .

Voici la ligne de commande à tirer de tous vos référentiels git, qu’ils soient ou non des sous-modules:

 ROOT=$(git rev-parse --show-toplevel 2> /dev/null) find "$ROOT" -name .git -type d -execdir git pull -v ';' 

Si vous l’exécutez dans votre repository git supérieur, vous pouvez remplacer "$ROOT" dans . .

Les réponses ci-dessus sont bonnes, mais nous avons utilisé git-hooks pour faciliter cela, mais il s’avère que dans git 2.14 , vous pouvez définir git config submodule.recurse sur true pour permettre aux sous-modules d’être mis à jour lorsque vous accédez à votre repository git.

Cela aura pour effet secondaire de pousser tous les changements de sous-modules que vous avez s’ils sont sur des twigs, mais si vous avez besoin de ce comportement, cela pourrait déjà faire l’affaire.

Je pense que vous devrez écrire un script pour le faire. Pour être honnête, je pourrais installer python pour le faire afin que vous puissiez utiliser os.walk pour cd dans chaque répertoire et émettre les commandes appropriées. L’utilisation de python ou d’un autre langage de script, autre que le traitement par lots, vous permet d’append / supprimer facilement des sous-projets sans avoir à modifier le script.

Remarque: pas trop facile, mais réalisable et qui a ses propres avantages.

Si l’on veut cloner uniquement la révision HEAD d’un référentiel et uniquement les HEAD de tous ses sous-modules (c.-à-d. Pour extraire “trunk”), alors on peut utiliser le script Lua suivant. Parfois, la commande simple git submodule update --init --recursive --remote --no-fetch --depth=1 peut entraîner une erreur git irrécupérable. Dans ce cas, il faut nettoyer le sous-répertoire du répertoire .git/modules et cloner le sous-module manuellement en utilisant la commande git clone --separate-git-dir . La seule complexité est de trouver l’ URL , le chemin du répertoire .git du sous-module et le chemin du sous-module dans l’arborescence du superprojet.

Remarque: le script est uniquement testé sur le référentiel https://github.com/boostorg/boost.git . Ses particularités: tous les sous-modules hébergés sur le même hôte et les mêmes .gitmodules contiennent uniquement des URL relatives.

 -- mkdir boost ; cd boost ; lua ../git-submodules-clone-HEAD.lua https://github.com/boostorg/boost.git . local module_url = arg[1] or 'https://github.com/boostorg/boost.git' local module = arg[2] or module_url:match('.+/([_%d%a]+)%.git') local branch = arg[3] or 'master' function execute(command) print('# ' .. command) return os.execute(command) end -- execute('rm -rf ' .. module) if not execute('git clone --single-branch --branch master --depth=1 ' .. module_url .. ' ' .. module) then io.stderr:write('can\'t clone repository from ' .. module_url .. ' to ' .. module .. '\n') return 1 end -- cd $module ; git submodule update --init --recursive --remote --no-fetch --depth=1 execute('mkdir -p ' .. module .. '/.git/modules') assert(io.input(module .. '/.gitmodules')) local lines = {} for line in io.lines() do table.insert(lines, line) end local submodule local path local submodule_url for _, line in ipairs(lines) do local submodule_ = line:match('^%[submodule %"([_%d%a]-)%"%]$') if submodule_ then submodule = submodule_ path = nil submodule_url = nil else local path_ = line:match('^%s*path = (.+)$') if path_ then path = path_ else submodule_url = line:match('^%s*url = (.+)$') end if submodule and path and submodule_url then -- execute('rm -rf ' .. path) local git_dir = module .. '/.git/modules/' .. path:match('^.-/(.+)$') -- execute('rm -rf ' .. git_dir) execute('mkdir -p $(dirname "' .. git_dir .. '")') if not execute('git clone --depth=1 --single-branch --branch=' .. branch .. ' --separate-git-dir ' .. git_dir .. ' ' .. module_url .. '/' .. submodule_url .. ' ' .. module .. '/' .. path) then io.stderr:write('can\'t clone submodule ' .. submodule .. '\n') return 1 end path = nil submodule_url = nil end end end