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

1848

Nous utilisons des sous-modules git pour gérer quelques grands projets qui dépendent de nombreuses autres bibliothèques que nous avons développées. Chaque bibliothèque est un dépôt distinct introduit dans le projet dépendant en tant que sous-module. Pendant le développement, nous voulons souvent aller chercher la dernière version de chaque sous-module dépendant.

Git a-t-il une commande intégrée pour ce faire? Sinon, que diriez-vous d'un fichier de commandes Windows ou similaire qui peut le faire?

Brad Robinson
la source
git-deep devrait vous aider.
Mathew Kurian
9
@Brad voulez-vous mettre à jour vos copies de sous-modules vers les revs de validation nommés dans le projet maître; ou souhaitez-vous extraire le dernier commit HEAD de chaque sous-module? La plupart des réponses ici concernent les premières; beaucoup de gens veulent ce dernier.
chrisinmtown

Réponses:

2467

Si c'est la première fois que vous extrayez un repo, vous devez d' --initabord l' utiliser :

git submodule update --init --recursive

Pour git 1.8.2 ou supérieur, l'option a --remoteété ajoutée pour prendre en charge la mise à jour des derniers conseils des succursales distantes:

git submodule update --recursive --remote

Cela a l'avantage supplémentaire de respecter toutes les branches "non par défaut" spécifiées dans les fichiers .gitmodulesou .git/config(si vous en avez, la valeur par défaut est origin / master, auquel cas certaines des autres réponses ici fonctionneraient également).

Pour git 1.7.3 ou supérieur, vous pouvez utiliser (mais les pièges ci-dessous concernant la mise à jour s'appliquent toujours):

git submodule update --recursive

ou:

git pull --recurse-submodules

si vous voulez tirer vos sous-modules vers les dernières validations au lieu de la validation actuelle vers laquelle le repo pointe.

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

Henrik Gustafsson
la source
299
Vous devriez probablement utiliser de git submodule update --recursivenos jours.
Jens Kohl
38
Amélioration des performances:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev
18
update mettra à jour chaque sous-module avec la révision spécifiée, et non avec la dernière mise à jour de ce référentiel.
Peter DeWeese
21
Juste pour ajouter, coller aveuglément origin masterà la fin de cette commande peut avoir des résultats inattendus si certains de vos sous-modules suivent un nom de branche ou d'emplacement différent de ce sous-module particulier. Évident pour certains, mais probablement pas pour tout le monde.
Nathan Hornby du
31
Juste pour clarifier pour tout le monde. git submodule update --recursiverecherche la révision que le référentiel parent a stockée pour chaque sous-module, puis vérifie cette révision dans chaque sous-module. Il ne tire PAS les derniers commits pour chaque sous-module. git submodule foreach git pull origin masterou git pull origin master --recurse-submodulesest ce que vous voulez si vous avez l'intention de mettre à jour chaque sous-module au plus tard à partir de leurs référentiels d'origine. Ce n'est qu'alors que vous obtiendrez les modifications en attente dans le référentiel parent avec des hachages de révision mis à jour pour les sous-modules. Enregistrez-les et vous êtes bon.
Chev
637
git pull --recurse-submodules --jobs=10

une fonctionnalité git apprise pour la première fois en 1.8.5.

Jusqu'à ce que le bug soit corrigé, pour la première fois, vous devez exécuter

mise à jour du sous-module git --init --recursive

Alexander Bartosh
la source
29
voté, j'utilise ceci: alias update_submodules = 'git pull --recurse-submodules && git submodule update'
Stephen C
3
Cela fonctionne si les sous-modules ont déjà été retirés au moins une fois, mais pour les sous-modules qui n'ont jamais été extraits, voir la réponse de gahooa ci-dessous.
Matt Browne
8
Cela affichera la version spécifiée par le référentiel supérieur; il ne tire PAS la tête. Par exemple, si TopRepo spécifie une version 2 derrière HEAD pour SubRepo, cela tirera SubRepo avec cette version qui est 2 derrière. D'autres réponses ici tirent HEAD dans SubRepo.
Chris Moschini
11
Notez que ni git pull --recurse-submodulesni git submodule update --recursivene pas initialize nouvellement ajouté sous - modules. Pour les initialiser, vous devez exécuter git submodule update --recursive --init. Citation du manuel : Si le sous-module n'est pas encore initialisé et que vous souhaitez simplement utiliser le paramètre tel qu'il est stocké dans .gitmodules, vous pouvez initialiser automatiquement le sous-module avec l'option --init.
patryk.beza
1
ajoutez peut-être un indice git submodule update --recursive --remotequi met également à jour les sous-modules vers la dernière révision à distance au lieu du SHA-1 stocké.
Hanno S.
386

À l'initialisation, exécutez la commande suivante:

git submodule update --init --recursive

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

Cela tirera 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.<name>.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 git repo, fonctionne le mieux pour moi.

Cela tirera tous les derniers sous-modules, y compris.

abc123
la source
10
Oui - la réponse la plus votée était la meilleure façon de le faire en 2009, mais c'est certainement plus simple et plus intuitif maintenant.
Michael Scott Cuthbert
2
@MichaelScottCuthbert merci, je suis sûr que dans 3 ans, cette commande sera folle aussi
abc123
5
Néanmoins, cela n'extrait pas la dernière révision du sous-module, seulement la dernière révision que le parent suit.
Nathan Osman
4
@NathanOsman qui est ce que vous voulez ... vous vous retrouverez avec du code cassé en ne suivant pas le suivi de révision des parents. Si vous êtes le responsable du parent, vous pouvez les mettre à jour vous-même et les valider.
abc123
2
Oui, mais d'après ma compréhension, ce n'est pas ce que le PO voulait.
Nathan Osman
305

Remarque: cela date de 2009 et peut-être bien alors, mais il existe de meilleures options maintenant.

Nous utilisons cela. Cela s'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 :)

Mise à jour:

En réponse au commentaire de l'auteur original sur le retrait de toutes les TÊTES de tous les sous-modules - c'est une bonne question.

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

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

  1. vérifier les git submodule statusréférentiels "modifiés". Le premier caractère des lignes de sortie l'indique. Si un sous-repo est modifié, vous ne voudrez PAS continuer.
  2. pour chaque dépôt répertorié, cd dans son répertoire et exécutez 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 inciter à tout ajouter et à valider?

Je voudrais mentionner que ce style n'est pas vraiment ce pour quoi les sous-modules git ont été conçus. En règle générale, vous voulez dire que "LibraryX" est à la version "2.32" et restera ainsi jusqu'à ce que je lui dise de "mettre à niveau".

C'est, dans un sens, ce que vous faites avec le script décrit, mais de manière plus automatique. Il faut faire attention!

Mise à jour 2:

Si vous êtes sur une plate-forme Windows, vous voudrez peut-être envisager d'utiliser Python pour implémenter le script car il est très capable dans ces domaines. Si vous êtes sous unix / linux, alors je suggère juste un script bash.

Besoin de clarifications? Postez simplement un commentaire.

gahooa
la source
Je ne pense pas que c'est ce que je veux. Cela ne tirera pas la version des sous-modules avec lesquels le super-projet a été engagé pour la dernière fois. Je veux extraire la version tête de tous les sous-modules.
Brad Robinson
3
Cela fonctionne très bien et fonctionne non seulement pour mettre à jour les sous-modules, mais aussi pour les récupérer pour la première fois si c'est ce dont vous avez besoin.
Matt Browne
Je reçois simplement "Il n'y a pas d'informations de suivi pour la branche actuelle. Veuillez spécifier la branche avec laquelle vous souhaitez fusionner." Peu importe ce que j'essaye: /
Nathan Hornby
9
Pourquoi ne pas lui créer un alias? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'puis l'utiliser comme git pupsans aucun script.
fracz
Merci, pour une raison quelconque, même si j'ai git 1.9.1, je devais effectuer git submodule initaprès la première traction avec des sous-modules inclus, afin que tout commence à fonctionner correctement.
Ben Usman
164

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

git submodule foreach git pull origin master

et,

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

Cela parcourra tous les sous-modules initialisés et exécutera les commandes données.

mturquette
la source
144

Ce qui suit a fonctionné pour moi sur Windows.

git submodule init
git submodule update
zachleat
la source
6
Ce n'est clairement pas ce que le PO a demandé. Il ne mettra à jour que la validation du sous-module associé et non la dernière.
Patrick
52
C'est cependant la seule chose sur cette page qui a permis à git de tirer des sous-modules la première fois que j'ai vérifié un
dépôt
2
Peut également utiliser: git submodule update --init --recursive (en particulier si le sous-module en question est RestKit d'un nouveau clone)
HCdev
33

Modifier :

Dans les commentaires, il a été souligné (par philfreo ) que la dernière version est requise. S'il existe des sous-modules imbriqués qui doivent être dans leur dernière version:

git submodule foreach --recursive git pull

----- Commentaire obsolète ci-dessous -----

N'est-ce pas la façon officielle de procéder?

git submodule update --init

Je l'utilise à chaque fois. Aucun problème jusqu'à présent.

Éditer:

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, c'est-à-dire les dépendances.

antitoxique
la source
5
Votre réponse ne répond pas à la question du PO, mais pour faire ce que vous avez proposé, vous pouvez simplement diregit submodule update --init --recursive
philfreo
2
Je vois, la dernière version est nécessaire. Eh bien, cela pourrait être utile s'il y a des sous-modules imbriqués: git submodule foreach --recursive git pull
antitoxique
1
Je ne pouvais en aucun cas télécharger quoi que ce soit - "git submodule update --init --recursive" a cependant fonctionné pour moi.
BrainSlugs83
33

Comme il peut arriver que la branche par défaut de vos sous-modules ne soit pasmaster , 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'
Sébastien Varrette
la source
parmi les nombreuses réponses aux nombreuses questions, celle-ci a fonctionné pour moi (2019, erreur github avec des identifiants de hachage spécifiques)
philshem
30

Première fois

Sous-module Clone et Init

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

Du repos

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

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

Mettre à jour le sous-module Git vers le dernier commit sur l'origine

git submodule foreach git pull origin master

Le moyen préféré doit être ci-dessous

git submodule update --remote --merge

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

Yash
la source
J'ai fait un clone git sans sous-modules par erreur et toutes les autres options n'ont pas fonctionné, personne n'a cloné de sous-modules. En utilisant le vôtre, a git submodule updatefait l'affaire. Maintenant, je télécharge des données de sous-modules manquantes dans la première étape du clone. Je vous remercie. Je ne suis pas bon en git: C
m3nda
Cet anser est en fait une très bonne réponse pour poser une question ici en haut: pourquoi dois-je ".. --recursive-submodules .." et puis en plus la "... update ..." et même ".. .foreach ... "plus tard pour obtenir le dernier commit? Tout cela ne ressemble pas du tout à GIT! Que fait «mise à jour» et pourquoi dois-je aller manuellement à chaque module pour tirer? N'est-ce pas ce que fait "... --recurse-submodules .."? Des indices?
Peter Branforn
20

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 également git pullpour mettre à jour le référentiel racine:

git pull && git submodule update --recursive
Jens Kohl
la source
10

Les réponses ci-dessus sont bonnes, mais nous utilisions git-hooks pour rendre cela plus facile, mais il s'avère que dans git 2.14 , vous pouvez définir git config submodule.recursetrue pour activer les sous-modules à mettre à jour lorsque vous tirez vers votre référentiel git.

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

Peut être fait en utilisant:

git config submodule.recurse true
JamesD
la source
Je dois aimer cette option, mais je dois malheureusement encore l'utiliser git submodule initavant la main si votre sous-module n'est pas encore initialisé.
Pellet
5

Git pour Windows 2.6.3 :

git submodule update --rebase --remote

Séoul
la source
C'est le seul qui a fonctionné pour moi. Je n'ai même pas pu lancer ou mettre à jour car le pointeur du sous-module pointait vers une version qui n'était plus dans la télécommande
Pavel P
4

Du niveau supérieur dans le référentiel:

git submodule foreach git checkout develop
git submodule foreach git pull

Cela va changer toutes les branches pour développer et tirer les dernières

Srayan Guhathakurta
la source
2
Ne fonctionne pas pour moi, avec git 2.7.
Bruno Haible
Avez-vous quelque chose comme un fichier sln Everything qui ajoute toutes les références de projet dans l'arborescence? Quelle erreur voyez-vous également? Pouvez-vous vérifier votre fichier gitignore aussi
Srayan Guhathakurta
1
git submodule foreach git pull origin masterJ'ai dû ajouter la branche que je voulais récupérer. à part ça, fonctionnait parfaitement.
Torxed
3

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 .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 ça 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 référentiel de configuration d'environnement .

À M
la source
3

Tout ce que vous devez faire maintenant est simple git checkout

Assurez-vous simplement de l'activer via cette configuration globale: git config --global submodule.recurse true

Pastille
la source
2

Voici la ligne de commande pour extraire 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 référentiel git supérieur, vous pouvez le remplacer "$ROOT"dans ..

kenorb
la source
1

Je pense que vous devrez écrire un script pour ce faire. Pour être honnête, je peux installer python pour le faire afin que vous puissiez utiliser os.walkto cdpour chaque répertoire et émettre les commandes appropriées. L'utilisation de python ou d'un autre langage de script, autre que batch, vous permettrait d'ajouter / supprimer facilement des sous-projets sans avoir à modifier le script.

baudtack
la source
1

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

Si l'on veut cloner uniquement la HEADrévision d'un référentiel et seulement HEADs de tous ses sous-modules (c'est-à-dire pour extraire "trunk"), alors on peut utiliser le script Lua suivant . Parfois, une simple commande git submodule update --init --recursive --remote --no-fetch --depth=1peut entraîner une giterreur irrécupérable . Dans ce cas, il faut nettoyer le sous-répertoire du .git/modulesrépertoire et cloner le sous-module manuellement à l'aide de la git clone --separate-git-dircommande. La seule complexité est de trouver l' URL , le chemin du .gitrépertoire du sous-module et le chemin du sous-module dans l'arborescence du superprojet.

Remarque: le script n'est testé que par rapport au https://github.com/boostorg/boost.gitréférentiel. Ses particularités: tous les sous-modules hébergés sur le même hôte et .gitmodulesne contiennent que 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
Tomilov Anatoliy
la source