Comment fonctionne git submodule add -b
?
Après l'ajout d'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 status
sur le sous-module affiche "Pas actuellement sur aucune branche") .
Je ne trouve aucune information sur .gitmodules
ou .git/config
à propos de la branche du sous-module ou d'un commit spécifique. Comment Git le comprend-il?
Aussi, est-il possible de spécifier une balise au lieu d'une branche?
J'utilise la version 1.6.5.2.
Remarque: Git 1.8.2 a ajouté la possibilité de suivre les branches. Voir certaines des réponses ci-dessous.
Il est un peu déroutant de s'habituer à cela, mais les sous-modules ne sont pas sur une branche. Comme vous le dites, ils sont simplement un pointeur sur un commit particulier 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 effectue la mise à jour de sous-module git, le sous-module est extrait pour ce commit spécifique.
C'est très bien 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 remplacé par cette balise fait ceci.
git pull
git submodule update --init
git pull
modifications qui engagent leurs points de répertoire de sous-modules. git submodule update
fusionne dans le nouveau code.
J'aimerais ajouter une réponse ici qui n'est en réalité qu'un conglomérat d'autres réponses, mais je pense qu'elle est peut-être plus complète.
Vous savez que vous avez un sous-module Git lorsque vous avez ces deux choses.
Votre .gitmodules
a une entrée comme ceci:
[submodule "SubmoduleTestRepo"]
path = SubmoduleTestRepo
url = https://github.com/jzaccone/SubmoduleTestRepo.git
Vous avez un objet de sous-module (nommé SubmoduleTestRepo dans cet exemple) dans votre référentiel Git. GitHub les montre comme des objets "sous-modules". Ou bien faites git submodule status
à partir 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 d'un commit spécifique.
Chaque fois que vous faites un git submodule update
, il remplira votre sous-module avec le contenu du commit. Il sait où trouver le commit à cause des informations contenues dans le .gitmodules
.
Maintenant, tout ce que le -b
fait est d'ajouter une ligne dans votre fichier .gitmodules
. En 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 branche est pris en charge dans un fichier
.gitmodules
, 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 à l'aide de "git add .
", par exemple commegit add ./SubmoduleTestRepo
, et vous n'avez pas besoin de changez le fichier.gitmodules
à chaque fois)
L'objet de sous-module pointe toujours sur un commit spécifique. La seule chose que l'option -b
vous achète est la possibilité d'ajouter un indicateur --remote
à votre mise à jour, conformément à la réponse de Vogella:
git submodule update --remote
Au lieu de renseigner le contenu du sous-module dans la validation indiquée par le sous-module, il remplace celle-ci par la dernière validation de la branche maître, PUIS il remplit le sous-module avec cette validation. Cela peut être fait en deux étapes par djacobs7 answer. Puisque vous avez maintenant mis à jour le commit sur lequel pointe l'objet de sous-module, vous devez valider l'objet de sous-module modifié dans votre référentiel Git.
git submodule add -b
n'est pas un moyen magique de tout mettre à jour avec une branche. Il ajoute simplement des informations sur une branche dans le fichier .gitmodules
et vous donne la possibilité de mettre à jour l'objet de sous-module avec la dernière validation d'une branche spécifiée avant de le renseigner.
(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 n'est pas encore en train de suivre une branche, alors ( si vous avez git 1.8.2 + ):
Assurez-vous que le référent parent sait que son sous-module suit maintenant 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
_
(avec 'Origine' étant le nom du dépôt distant en amont à partir duquel le sous-module a été cloné.
Un _git remote -v
_ à l'intérieur de ce sous-module l'affichera. Habituellement, c'est 'Origine')
N'oubliez pas d'enregistrer le nouvel état de votre sous-module dans votre dépôt principal:
_cd /path/to/your/parent/repo
git add path/to/your/submodule
git commit -m "Make submodule tracking a branch"
_
Les mises à jour ultérieures pour ce sous-module devront utiliser l'option _--remote
_:
_# 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 succursale est enregistré sous la forme _
submodule.<name>.branch
_ dans _.gitmodules
_ pour _update --remote
_.
ne valeur spéciale de _.
_ est utilisée pour indiquer que le nom de la branche dans le sous-module doit être identique à celui de la branche actuelle dans le référentiel actuel.
Si vous souhaitez mettre à jour tous vos sous-modules après une branche:
_ git submodule update --recursive --remote
_
Notez que le résultat, pour chaque sous-module mis à jour, sera presque toujours un HEAD détaché, comme Dan Cameron note dans sa réponse .
( Clintm note dans les commentaires que, si vous exécutez _git submodule update --remote
_ et que le résultat sha1 est identique à la branche sur laquelle se trouve actuellement le sous-module, il ne le sera pas. faire quoi que ce soit et laisser le sous-module toujours "sur cette branche" et non dans un état isolé.)
Pour s'assurer que la branche est réellement extraite (et que cela ne modifiera pas le SHA1 du entrée spéciale représentant le sous-module du référentiel parent), il suggère:
_git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch'
_
Chaque sous-module fera toujours référence au 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 le sous-module doit suivre.
Après ce Push dans un sous-module, n'oubliez pas de revenir au référent parent, ajoutez, validez et envoyez le nouveau SHA1 pour ces sous-modules modifiés.
Notez l'utilisation de _$toplevel
_, recommandé dans les commentaires par Alexander Pogrebnyak .
_$toplevel
_ a été introduit dans git1.7.2 en mai 2010: commit f030c96 .
il contient le chemin absolu du répertoire de niveau supérieur (où _
.gitmodules
_ est).
dtmland
ajoute dans les commentaires :
Le script foreach ne pourra pas extraire les sous-modules qui ne suivent pas de 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' –
_
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 checkout $branch' –
_
mläute affine la commande de dtmland avec une version simplifiée dans les commentaires :
_git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
_
plusieurs lignes:
_git submodule foreach -q --recursive \
'git checkout \
$(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
_
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
Un exemple de la façon dont j'utilise les sous-modules Git.
Et ça ressemble un peu à ça:
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 ça aide (même si j'utilise un tag et non une branche)?
Selon mon expérience, changer de branche dans le superprojet ou dans les prochaines commandes causera toujours le détachement de têtes de sous-modules, que le sous-module soit correctement ajouté et suivi (c'est-à-dire que @ djacobs7 et @Johnny Z répondent).
Et au lieu de vérifier manuellement la branche appropriée manuellement ou via un script git submodule foreach peut être utilisé.
Ceci vérifiera le fichier de configuration du sous-module pour la propriété branch et extraira la branche définie.
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
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 la dernière validation sur une branche, comme on pourrait s'y attendre.
Cela a du sens quand vous y réfléchissez. Supposons que je crée un référentiel foo avec un sous-module barre . Je pousse mes modifications et je vous dis de vérifier le commit a7402be du dépôt foo .
Ensuite, imaginez que quelqu'un commette une modification de la barre de référentiel avant de pouvoir créer votre clone.
Lorsque vous extrayez commit a7402be du référentiel foo , vous vous attendez à obtenir le même code que celui que j'ai poussé. C'est pourquoi les sous-modules ne sont pas mis à jour tant que vous ne leur avez pas dit explicitement, puis effectuez un nouveau commit.
Personnellement, je pense que les sous-modules sont la partie la plus déroutante de Git. Beaucoup de lieux peuvent expliquer les sous-modules mieux que moi. Je recommande Pro Git par Scott Chacon.
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.gitmodules
pour le modifierpath = ...
et url = ...
qui dit branch = your-branch
, pour chaque sous-module; enregistrer le fichier .gitmodules
.$ git submodule update --remote
... cela devrait inclure les derniers commits sur la branche spécifiée, pour chaque sous-module ainsi modifié.
J'ai ceci dans mon fichier .gitconfig. C'est encore une ébauche, mais 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-"
Nous utilisons Quack pour extraire un module spécifique d’un autre référentiel Git. Nous devons extraire le code sans la base de code complète du référentiel fourni - nous avons besoin d'un module/fichier très spécifique à partir de cet énorme référentiel et nous devrions le mettre à jour à chaque fois que nous exécutons update.
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 courir
$ quack
Et il tire le code des configurations ci-dessus.
Le seul effet du choix d’une branche pour un sous-module est que, chaque fois que vous passez l’option --remote
dans la ligne de commande git submodule update
, Git extrait en HEAD mode (si le comportement par défaut --checkout
_ est sélectionné), la dernière validation de cette branche distante sélectionnée.
Vous devez être particulièrement prudent lorsque vous utilisez cette fonctionnalité de suivi de branche distante 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 IS IS NOT celle qui sera clonée pendant git submodule update --remote
. Si vous transmettez également le paramètre --depth
et et , vous n'indiquez pas à Git quelle branche vous souhaitez cloner - et en réalité vous ne pouvez pas dans la ligne de commande git submodule update
!! -, il se comportera implicitement comme expliqué dans la documentation git-clone(1)
de git clone --single-branch
lorsque le paramètre explicite --branch
est manquant, et donc il ne clonera que la branche principale =.
Sans surprise, après la phase de clonage effectuée par la commande git submodule update
, il va finalement essayer de vérifier le dernier commit pour la branche remote que vous avez précédemment configurée pour le sous-module, et, si ce n'est pas le principal, il ne fait pas partie de votre clone peu profond local, et donc il échouera avec
fatal: Nécessité d'une seule révision
Impossible de trouver l'origine actuelle/( NotThePrimaryBranch révision dans le chemin de sous-module 'mySubmodule'
sous-module git add -b develop --name nom-branche - https: //branch.git