Comment puis-je spécifier une branche / balise lors de l'ajout d'un sous-module Git?

756

Comment ça git submodule add -bmarche?

Après avoir ajouté un sous-module avec une branche spécifique, un nouveau référentiel cloné (après git submodule update --init) sera à un commit spécifique, pas la branche elle-même ( git statussur le sous-module affiche "Pas actuellement sur une branche").

Je ne trouve aucune information sur .gitmodulesou à .git/configpropos de la branche du sous-module ou d'un commit spécifique, alors comment Git peut-il le comprendre?

Est-il également possible de spécifier une balise au lieu d'une branche?

J'utilise la version 1.6.5.2.

Ivan
la source
3
Si vous avez un sous-module existant qui ne suit pas encore une branche , mais que vous souhaitez qu'il le fasse maintenant, il suivrait une branche ... voir ma réponse ci
VonC

Réponses:

745

Remarque: Git 1.8.2 a ajouté la possibilité de suivre les branches. Voir certaines des réponses ci-dessous.


C'est un peu déroutant de s'y habituer, mais les sous-modules ne sont pas sur une branche. Ils ne sont, comme vous le dites, qu'un pointeur vers une validation particulière du référentiel du sous-module.

Cela signifie que lorsque quelqu'un d'autre extrait votre référentiel, ou extrait votre code, et met à jour le sous-module git, le sous-module est extrait pour ce commit particulier.

C'est idéal pour un sous-module qui ne change pas souvent, car alors tout le monde sur le projet peut avoir le sous-module au même commit.

Si vous souhaitez déplacer le sous-module vers une balise particulière:

cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push

Ensuite, un autre développeur qui souhaite que submodule_directory soit modifié pour cette balise, le fait

git pull
git submodule update --init

git pullles modifications qui valident leur répertoire de sous-module pointe vers. git submodule updatefusionne réellement dans le nouveau code.

djacobs7
la source
8
C'est une très bonne explication, merci! Et bien sûr, après avoir lu votre réponse, j'ai réalisé que la validation était enregistrée dans le sous-module lui-même (sous-module / .git / HEAD).
Ivan
4
Cela ne semble pas fonctionner avec git 1.7.4.4. cd my_submodule; git checkout [ref in submodule's repositoryrendements fatal: reference is not a tree: .... C'est comme si gitne fonctionnerait que sur le référentiel parent.
James A. Rosen
3
Il est bon d'utiliser des sous-modules git même pour des projets qui sont souvent mis à jour. Le noyau Linux l'utilise et ce n'est pas si mal
10
Est-ce git checkout v1.0une branche ou un tag?
Bernhard Döbler du
8
Considérez une balise comme un alias lisible par l'homme pour une validation. Et une validation est un ensemble d'états spécifiques pour chaque fichier. Une branche est essentiellement la même chose, sauf que vous pouvez y apporter des modifications.
deadbabykitten
657

J'aimerais ajouter ici une réponse qui n'est en réalité qu'un conglomérat d'autres réponses, mais je pense qu'elle pourrait être plus complète.

Vous savez que vous avez un sous-module Git lorsque vous avez ces deux choses.

  1. Votre .gitmodulesa une entrée comme ceci:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. Vous avez un objet sous-module (nommé SubmoduleTestRepo dans cet exemple) dans votre référentiel Git. GitHub les présente comme des objets "sous-modules". Ou faites à git submodule statuspartir d'une ligne de commande. Les objets de sous-module Git sont des types spéciaux d'objets Git, et ils contiennent les informations SHA pour une validation spécifique.

    Chaque fois que vous effectuez un git submodule update, il remplira votre sous-module avec le contenu de la validation. Il sait où trouver le commit à cause des informations contenues dans le fichier .gitmodules.

    Maintenant, tout ce qu'il -bfaut, c'est ajouter une ligne dans votre .gitmodulesfichier. Donc, suivant le même exemple, cela ressemblerait à ceci:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
        branch = master
    

    Remarque: seul le nom de la branche est pris en charge dans un .gitmodulesfichier, mais SHA et TAG ne sont pas pris en charge! (au lieu de cela, la validation de la branche de chaque module peut être suivie et mise à jour en utilisant " git add .", par exemple comme git add ./SubmoduleTestRepo, et vous n'avez pas besoin de changer le .gitmodulesfichier à chaque fois)

    L'objet sous-module pointe toujours sur une validation spécifique. La seule chose que l' -boption vous achète est la possibilité d'ajouter un --remoteindicateur à votre mise à jour selon la réponse de Vogella:

    git submodule update --remote
    

    Au lieu de renseigner le contenu du sous-module sur la validation pointée par le sous-module, il remplace cette validation par la dernière validation sur la branche principale, PUIS il remplit le sous-module avec cette validation. Cela peut se faire en deux étapes par réponse djacobs7. Puisque vous avez maintenant mis à jour la validation vers laquelle l'objet du sous-module pointe, vous devez valider l'objet de sous-module modifié dans votre référentiel Git.

    git submodule add -bn'est pas un moyen magique de tout garder à jour avec une branche. Il ajoute simplement des informations sur une branche dans le .gitmodulesfichier et vous donne la possibilité de mettre à jour l'objet de sous-module à la dernière validation d'une branche spécifiée avant de le remplir.

Johnny Z
la source
14
Cette réponse devrait avoir plus de votes positifs. J'ai lu de nombreux articles la journée dernière et cela dissipe toute confusion. Venant du monde SVN et utilisant des externes - on veut croire que le suivi de branche de sous-module git garde par magie tout à jour de la branche - mais ce n'est pas vrai! Vous devez les mettre à jour explicitement! Comme vous le mentionnez, vous devez valider les objets de sous-module modifiés.
dtmland
12
Ce suivi de branche fonctionne-t-il également avec les balises ? Au lieu d'une branche, j'ai spécifié une balise dans mon .gitmoduleset après avoir $ git submodule update --init --remote TestModulefait une erreur disant fatal: Needed a single revisionet Unable to find current origin/TestTag revision in submodule path 'TestModule'. Lorsque vous le faites avec une vraie branche, cela fonctionne. Est-il possible de spécifier une balise .gitmodulessans avoir à spécifier le commit exact?
Hhut
5
Cela ne semble pas fonctionner. J'ai mis à jour le hachage .gitmoduleset j'ai couru git submodule updateet il ne s'est rien passé?
CMCDragonkai
2
D'une certaine manière, cela ne fonctionne pas pour moi. Avec un ID de validation SHA, j'obtiens toujours une erreur "Impossible de trouver la révision actuelle (j'ai vérifié le numéro de révision de HEAD et son correct). Cependant, si j'utilise master, cela fonctionne.
infoclogged
2
La saisie d'un SHA dans l'attribut de branche ne fonctionne pas non plus pour moi. Cette utilisation n'est pas non plus prise en charge par les documents: git-scm.com/docs/gitmodules
Jakub Bochenski
340

(Git 2.22, Q2 2019, a introduit git submodule set-branch --branch aBranch -- <submodule_path>)

Notez que si vous avez un sous-module existant qui ne suit pas encore une branche , alors ( si vous avez git 1.8.2+ ):

  • Assurez-vous que le dépôt parent sait que son sous-module suit désormais une branche:

    cd /path/to/your/parent/repo
    git config -f .gitmodules submodule.<path>.branch <branch>
    
  • Assurez-vous que votre sous-module est bien au plus tard de cette branche:

    cd path/to/your/submodule
    git checkout -b branch --track origin/branch
      # if the master branch already exist:
      git branch -u origin/master master
    

         («origine» étant le nom du référentiel distant en amont à partir duquel le sous-module a été cloné.
         Un git remote -vintérieur de ce sous-module l'affichera. Généralement, il s'agit de «origine»)

  • N'oubliez pas d'enregistrer le nouvel état de votre sous-module dans votre référentiel parent:

    cd /path/to/your/parent/repo
    git add path/to/your/submodule
    git commit -m "Make submodule tracking a branch"
    
  • La mise à jour ultérieure de ce sous-module devra utiliser l' --remoteoption:

    # update your submodule
    # --remote will also fetch and ensure that
    # the latest commit from the branch is used
    git submodule update --remote
    
    # to avoid fetching use
    git submodule update --remote --no-fetch 
    

Notez qu'avec Git 2.10+ (Q3 2016), vous pouvez utiliser ' .' comme nom de branche:

Le nom de la branche est enregistré comme submodule.<name>.branchdans .gitmodulespour update --remote.
Une valeur spéciale de .est utilisée pour indiquer que le nom de la branche dans le sous-module doit être le même nom que la branche actuelle dans le référentiel actuel .

Mais, comme commenté par LubosD

Avec git checkout, si le nom de la branche à suivre est " .", cela tuera votre travail non engagé!
Utilisez git switchplutôt.

Cela signifie Git 2.23 (août 2019) ou plus.

Voir " Confus pargit checkout "


Si vous souhaitez mettre à jour tous vos sous-modules en suivant une branche:

    git submodule update --recursive --remote

Notez que le résultat, pour chaque sous-module mis à jour, sera presque toujours une tête détachée , comme le note Dan Cameron dans sa réponse .

( Clintm note dans les commentaires que, si vous exécutez git submodule update --remoteet que le sha1 résultant est le même que la branche sur laquelle le sous-module est actuellement, il ne fera rien et laissera le sous-module toujours "sur cette branche" et non dans un état de tête détachée. )

Pour s'assurer que la branche est réellement extraite (et cela ne modifiera pas le SHA1 de l' entrée spéciale représentant le sous-module pour le référentiel parent), il suggère:

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'

Chaque sous-module référencera toujours le même SHA1, mais si vous effectuez de nouveaux commits, vous pourrez les pousser car ils seront référencés par la branche que vous souhaitez que le sous-module suive.
Après cette poussée dans un sous-module, n'oubliez pas de revenir au référentiel parent, d'ajouter, de valider et de pousser le nouveau SHA1 pour ces sous-modules modifiés.

Notez l'utilisation de $toplevel, recommandée dans les commentaires d' Alexander Pogrebnyak .
$toplevela été introduit dans git1.7.2 en mai 2010: commit f030c96 .

il contient le chemin absolu du répertoire de niveau supérieur (où .gitmodulesest).

dtmlandajoute dans les commentaires :

Le script foreach ne parviendra pas à extraire les sous-modules qui ne suivent pas une branche.
Cependant, cette commande vous donne les deux:

 git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git switch $branch' –

La même commande mais plus facile à lire:

git submodule foreach -q --recursive \
    'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
     [ "$branch" = "" ] && \
     git checkout master || git switch $branch' –

umläute affine la commande de dtmland avec une version simplifiée dans les commentaires :

git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

plusieurs lignes:

git submodule foreach -q --recursive \
  'git switch \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

Avant Git 2.26 (T1 2020), une extraction à laquelle il est demandé de récupérer récursivement les mises à jour dans les sous-modules produit inévitablement des rames de sortie, et il devient difficile de repérer les messages d'erreur.

La commande a appris à énumérer les sous-modules qui avaient des erreurs à la fin de l'opération .

Voir commit 0222540 (16 janvier 2020) par Emily Shaffer ( nasamuffin) .
(Fusionné par Junio ​​C Hamano - gitster- en commit b5c71cc , 05 fév 2020)

fetch: accentuer l'échec lors de la récupération du sous-module

Signé par: Emily Shaffer

Dans les cas où une extraction de sous-module échoue alors qu'il y a plusieurs sous-modules, l'erreur de la seule extraction de sous-module échouée est enterrée sous l'activité sur les autres sous-modules si plus d'une extraction est retombée fetch-by-oid.
Signalez un échec tardivement afin que l'utilisateur sache que quelque chose s'est mal passé et où .

Parce que fetch_finish()est uniquement appelé de manière synchrone par run_processes_parallel,mutexage n'est pas nécessaire autour submodules_with_errors.

VonC
la source
1
Question: si j'ai un dossier subModule1 et que je souhaite suivre la branche principale, la commande résultante ressemblerait-elle à ceci: git config -f .gitmodules submodule.subModule1.branch master
BraveNewMath
1
Le foreachscript ne dépendra pas du code en dur <path>, si vous le remplacez <path>par $toplevel/.
Alexander Pogrebnyak
1
Le foreachscript ne parviendra pas à extraire les sous-modules qui ne suivent pas une branche. Cependant, cette commande vous donne les deux:git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch'
dtmland
2
voici une version simplifiée du script de @ dtmland:git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
umläute
1
Ohh! En fait, le script foreach n'est pas nécessaire. Nous devons exécuter la mise à jour du sous-module avec le commutateur --merge ou --rebase: git submodule update --remote --mergeou git submodule update --remote --rebase. Ces commandes effectuent le suivi de la branche distante.
GregTom
206

Git 1.8.2 a ajouté la possibilité de suivre les branches.

# add submodule to track master branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

Voir aussi sous-modules Git

vogella
la source
4
Est-ce que cela s'applique également aux tags?
ThorSummoner
1
Comment l'ajout d'un sous-module de cette manière se reflète-t-il dans le .gitmodulesfichier?
Eugene
1
Merci, je viens d'utiliser les informations sur pour m'aider à créer un dossier de sous-module qui est synchronisé avec un site Web GitHub gh-pages: exemple complet sur github.com/o2platform/fluentnode/issues/22
Dinis Cruz
4
Vous pouvez verrouiller une étiquette avec git submodule add -b tags/<sometag> <url>laquelle vous pouvez voir la ligne branch = tags/<sometag>en.gitmodules
KCD
9
@KCD Quelle version de git peut le faire avec des balises. Le mien ne fonctionne pas?
CMCDragonkai
58

Un exemple de la façon dont j'utilise les sous-modules Git.

  1. Créer un nouveau référentiel
  2. Ensuite, clonez un autre référentiel en tant que sous-module
  3. Ensuite, nous avons ce sous-module utiliser une balise appelée V3.1.2
  4. Et puis nous nous engageons.

Et cela ressemble un peu à ceci:

git init 
vi README
git add README
git commit 
git submodule add git://github.com/XXXXX/xxx.yyyy.git stm32_std_lib
git status

git submodule init
git submodule update

cd stm32_std_lib/
git reset --hard V3.1.2 
cd ..
git commit -a

git submodule status 

Peut-être que cela aide (même si j'utilise une balise et non une branche)?

Johan
la source
4
C'est fondamentalement la même réponse que djacobs7, mais merci quand même :)
Ivan
1
Devriez-vous être en mesure de valider un changement après votre git reset --hard V3.1.2? Je reçois juste un "rien à valider" avec un git statusdu répertoire parent.
Nick Radford
1
@Ivan: Pourriez-vous expliquer comment cela est identique à la réponse de djacobs7? Pour autant que je vois, sa réponse n'inclut même pas la commande 'submodule add', au lieu de cela le dépôt est ajouté directement, sans aucun lien vers le dépôt git d'origine du module. Au moins, lorsque j'ai essayé cette approche, il n'y avait aucun lien dans .gitmodules.
Michel Müller
La réponse de djacobs7 ne comprend pas toute l'explication à partir de l'ajout du sous-module. Il suppose que vous l'avez déjà.
CodeMonkey
n'est-ce pas simplement ajouter tout le contenu du sous-module en tant qu'objets suivis à votre référentiel principal?
user1312695
38

D'après mon expérience, le changement de branche dans le superprojet ou les extractions futures entraînera toujours des TÊTES détachées de sous-modules, que le sous-module soit correctement ajouté et suivi (c.-à-d. Réponses @ djacobs7 et @Johnny Z).

Et au lieu de vérifier manuellement la branche correcte manuellement ou via un script git, le sous-module foreach peut être utilisé.

Cela vérifiera le fichier de configuration du sous-module pour la propriété de la branche et extraira la branche définie.

git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'

Dan Cameron
la source
Agréable. +1. J'ai inclus votre commande dans ma réponse .
VonC
33

Les sous-modules Git sont un peu étranges - ils sont toujours en mode "tête détachée" - ils ne sont pas mis à jour avec le dernier commit sur une branche comme on pourrait s'y attendre.

Cela a du sens quand on y pense, cependant. Disons que je crée un référentiel foo avec une barre de sous-module . Je pousse mes modifications et vous dis de vérifier le commit a7402be depuis le dépôt foo .

Imaginez ensuite que quelqu'un valide une modification de la barre de référentiel avant de pouvoir faire votre clone.

Lorsque vous extrayez commit a7402be à partir du référentiel foo , vous vous attendez à obtenir le même code que j'ai poussé. C'est pourquoi les sous-modules ne sont pas mis à jour tant que vous ne leur avez pas demandé explicitement de faire un nouveau commit.

Personnellement, je pense que les sous-modules sont la partie la plus déroutante de Git. Il y a beaucoup d'endroits qui peuvent expliquer les sous-modules mieux que moi. Je recommande Pro Git de Scott Chacon.

Neall
la source
Je pense qu'il est temps que je commence à lire quelques livres git, merci pour la recommandation.
Ivan
Désolé, mais vous n'avez pas précisé si l'on obtiendrait la même chose que vous avez poussé vers a7402be, ou si vous obtenez la dernière barre, bien que votre version de foo. Merci :)
mmm
6
Le problème est qu'il devrait y avoir une option pour dire "garder ce sous-module sur la branche X" afin que si vous VOULEZ qu'il se mette à jour automatiquement, vous pouvez y arriver. Cela rendrait les sous-modules beaucoup plus utiles pour gérer par exemple une installation WordPress où les plugins sont tous des dépôts Git sans avoir à réenregistrer le superprojet pour chaque plugin qui est mis à jour.
jerclarke
@jeremyclark git clone git://github.com/git/git.gitet pousser cette fonctionnalité ...? = D
Alastair
1
La partie la plus déroutante de Git est que même après plus d'une décennie de développement, un outil destiné à m'aider à faire mon travail a toujours une si mauvaise expérience utilisateur et pour des raisons complètement indépendantes de moi, les gens aiment se faire montrer le doigt par Git all le temps.
0xC0000022L
20

Pour changer de branche pour un sous-module (en supposant que vous avez déjà le sous-module dans le référentiel):

  • cd à la racine de votre référentiel contenant les sous-modules
  • Ouvert .gitmodulespour modification
  • Ajoutez la ligne ci path = ...- dessous et url = ...cela dit branch = your-branch, pour chaque sous-module; enregistrer le fichier .gitmodules.
  • puis sans changer de répertoire faire $ git submodule update --remote

... cela devrait générer les derniers commits sur la branche spécifiée, pour chaque sous-module ainsi modifié.

Ingénieur
la source
10

Je l'ai dans mon fichier .gitconfig. Il s'agit toujours d'un projet, mais il s'est avéré utile pour l'instant. Cela m'aide à toujours rattacher les sous-modules à leur branche.

[alias]

######################
#
#Submodules aliases
#
######################


#git sm-trackbranch : places all submodules on their respective branch specified in .gitmodules
#This works if submodules are configured to track a branch, i.e if .gitmodules looks like :
#[submodule "my-submodule"]
#   path = my-submodule
#   url = [email protected]/my-submodule.git
#   branch = my-branch
sm-trackbranch = "! git submodule foreach -q --recursive 'branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; git checkout $branch'"

#sm-pullrebase :
# - pull --rebase on the master repo
# - sm-trackbranch on every submodule
# - pull --rebase on each submodule
#
# Important note :
#- have a clean master repo and subrepos before doing this !
#- this is *not* equivalent to getting the last committed 
#  master repo + its submodules: if some submodules are tracking branches 
#  that have evolved since the last commit in the master repo,
#  they will be using those more recent commits !
#
#  (Note : On the contrary, git submodule update will stick 
#to the last committed SHA1 in the master repo)
#
sm-pullrebase = "! git pull --rebase; git submodule update; git sm-trackbranch ; git submodule foreach 'git pull --rebase' "

# git sm-diff will diff the master repo *and* its submodules
sm-diff = "! git diff && git submodule foreach 'git diff' "

#git sm-push will ask to push also submodules
sm-push = push --recurse-submodules=on-demand

#git alias : list all aliases
#useful in order to learn git syntax
alias = "!git config -l | grep alias | cut -c 7-"
Pascal T.
la source
3

Nous utilisons Quack pour extraire un module spécifique d'un autre référentiel Git. Nous devons extraire le code sans l'intégralité de la base de code du référentiel fourni - nous avons besoin d'un module / fichier très spécifique de cet immense référentiel et doit être mis à jour chaque fois que nous exécutons la mise à jour.

Nous l'avons donc réalisé de cette manière:

Créer une configuration

name: Project Name

modules:
  local/path:
    repository: https://github.com/<username>/<repo>.git
    path: repo/path
    branch: dev
  other/local/path/filename.txt:
    repository: https://github.com/<username>/<repo>.git
    hexsha: 9e3e9642cfea36f4ae216d27df100134920143b9
    path: repo/path/filename.txt

profiles:
  init:
    tasks: ['modules']

Avec la configuration ci-dessus, il crée un répertoire à partir du référentiel GitHub fourni comme spécifié dans la configuration du premier module, et l'autre consiste à extraire et à créer un fichier à partir du référentiel donné.

Les autres développeurs ont juste besoin de s'exécuter

$ quack

Et il tire le code des configurations ci-dessus.

Love Sharma
la source
2

Le seul effet du choix d'une branche pour un sous-module est que, chaque fois que vous passez l' --remoteoption dans la git submodule updateligne de commande, Git extrait en mode HEAD détaché (si le --checkoutcomportement par défaut est sélectionné) la dernière validation de cette branche distante sélectionnée .

Vous devez être particulièrement prudent lorsque vous utilisez cette fonction de suivi de branche à distance pour les sous-modules Git si vous travaillez avec des clones peu profonds de sous-modules. La branche que vous choisissez à cet effet dans les paramètres de sous-module N'EST PAS celle qui sera clonée pendant git submodule update --remote. Si vous passez également le --depthparamètre et que vous n'indiquez pas à Git sur quelle branche vous voulez cloner - et en fait vous ne pouvez pas dans la git submodule updateligne de commande !! -, il se comportera implicitement comme expliqué dans la git-clone(1)documentation git clone --single-branchlorsque le --branchparamètre explicite est manquant, et par conséquent il ne clonera que la branche primaire .

Sans surprise, après l'étape de clonage effectuée par la git submodule updatecommande, il va enfin essayer de vérifier la dernière validation de la branche distante que vous avez précédemment configurée pour le sous-module, et, si ce n'est pas la principale, elle ne fait pas partie de votre clone peu profond local, et donc il échouera avec

fatal: besoin d'une seule révision

Impossible de trouver l'origine actuelle / la révision NotThePrimaryBranch dans le chemin du sous-module 'mySubmodule'

LuKePicci
la source
comment corriger l'erreur - Besoin d'une seule révision?
NidhinSPradeep
-1

git submodule add -b develop --name branch-name - https: //branch.git

Passiondroid
la source