J'utilise des sous-modules GIT. Après avoir extrait les modifications du serveur, la tête de mon sous-module se détache souvent de la branche principale.
Pourquoi ça se passe?
Je dois toujours faire:
git branch
git checkout master
Comment puis-je m'assurer que mon sous-module pointe toujours vers la branche principale?
Personnellement, je déteste les réponses qui dirigent vers des liens externes qui risquent de ne plus fonctionner avec le temps et vérifient ma réponse here (sauf si la question est en double) - diriger vers la question qui couvre le sujet entre les lignes d'un autre sujet, mais globalement égale: "Je ne réponds pas, lisez la documentation."
Revenons donc à la question: pourquoi cela se produit-il?
La situation que vous avez décrite
Après avoir extrait les modifications du serveur, la tête de mon sous-module se détache souvent de la branche principale.
Ceci est un cas fréquent lorsque l'on n'utilise pas sous-modules trop souvent ou vient de commencer avec sous-modules . Je crois avoir raison de dire que nous avons tous été à un moment donné où notre sous-module ' s HEAD se détache.
$ cd <submodule-path>
# if the master branch already exists locally:
# (From git docs - branch)
# -u <upstream>
# --set-upstream-to=<upstream>
# Set up <branchname>'s tracking information so <upstream>
# is considered <branchname>'s upstream branch.
# If no <branchname> is specified, then it defaults to the current branch.
$ git branch -u <Origin>/<branch> <branch>
# else:
$ git checkout -b <branch> --track <Origin>/<branch>
<branch>
. $ git submodule add -b <branch> <repository> [<submodule-path>]
$ git submodule update --remote
$ cd <submodule-path>
$ git checkout <branch>
$ cd <parent-repo-path>
# <submodule-path> is here path releative to parent repo root
# without starting path separator
$ git config -f .gitmodules submodule.<submodule-path>.branch <branch>
Cependant, même si vous avez configuré votre sous-module pour suivre la branche correcte, vous pouvez toujours vous trouver dans des situations où votre sous-module obtient HEAD detached at <commit-hash>
Dans les cas courants, vous avez déjà résolu votre DETACHED HEAD puisqu'il était lié à l'un des problèmes de configuration ci-dessus. Mais rappelez-vous que votre référentiel parent ne gère plus l'état de votre sous-module (à l'aide d'un hachage de validation validé dans le référentiel parent), car votre sous-module suit sa propre branche distante, ce qui ouvre de nouvelles possibilités d'échec.
Exécutez $ git status
dans votre parent et également dans le chemin du sous-module pour vérifier que tout est suivi correctement et que tout est à jour, puis exécutez $ cd <parent-repo>
et git submodule update --remote
. Comme vous le voyez, si vous exécutez à nouveau le statut git, tout va bien pour le moment.
Pour démontrer que, lorsque tout semble configuré correctement et que vous ne vous attendez pas à être DÉTACHÉ HEAD les choses peuvent mal se passer, examinons ce qui suit:
$ cd <submodule-path> # and make modification to your submodule
$ git add .
$ git commit -m"Your modification" # Let's say you forgot to Push it to remote.
$ cd <parent-repo-path>
$ git status # you will get
Your branch is up-to-date with '<Origin>/<branch>'.
Changes not staged for commit:
modified: path/to/submodule (new commits)
# As normally you would commit new commit hash to your parent repo
$ git add -A
$ git commit -m"Updated submodule"
$ git Push <Origin> <branch>.
$ git status
Your branch is up-to-date with '<Origin>/<branch>'.
nothing to commit, working directory clean
# If you now update your submodule
$ git submodule update --remote
Submodule path 'path/to/submodule': checked out 'commit-hash'
$ git status # will show again that (submodule has new commits)
$ cd <submodule-path>
$ git status
HEAD detached at <hash>
# as you see you are DETACHED and you are lucky if you found out now
# since at this point you just asked git to update your submodule
# from remote master which is 1 commit behind your local branch
# since you did not Push you submodule chage commit to remote.
# Here you can fix it simply by. (in submodules path)
$ git checkout <branch>
$ git Push <Origin>/<branch>
# which will fix the states for both submodule and parent since
# you told already parent repo which is the submodules commit hash
# to track so you don't see it anymore as untracked.
Mais si vous parvenez déjà à apporter des modifications localement pour le sous-module et que vous les avez validées, les poussez à distance puis, lorsque vous exécutez 'git checkout', Git vous avertit:
$ git checkout <branch>
Warning: you are leaving 1 commit behind, not connected to any of your branches:
If you want to keep it by creating a new branch, this may be a good time to do so with:
L'option recommandée pour créer une branche temporaire peut être bonne, puis vous pouvez simplement fusionner ces branches, etc. Cependant, personnellement, je n'utiliserais que git cherry-pick <hash>
dans ce cas.
$ git cherry-pick <hash> # hash which git showed you related to DETACHED HEAD
# if you get 'error: could not apply...' run mergetool and fix conflicts
$ git mergetool
$ git status # since your modifications are staged just remove untracked junk files
$ rm -rf <untracked junk file(s)>
$ git commit # without arguments
# which should open for you commit message from DETACHED HEAD
# just save it or modify the message.
$ git Push <Origin> <branch>
$ cd <parent-repo-path>
$ git add -A # or just the unstaged submodule
$ git commit -m"Updated <submodule>"
$ git Push <Origin> <branch>
Bien que dans certains cas, vos sous-modules puissent passer à l'état DETACHED HEAD, j'espère que vous comprendrez maintenant un peu plus comment déboguer votre cas particulier.
j'en ai marre de toujours le détacher, alors je viens d'utiliser un script Shell pour le construire pour tous mes modules. Je suppose que tous les sous-modules sont sur master: voici le script:
#!/bin/bash
echo "Good Day Friend, building all submodules while checking out from MASTER branch."
git submodule update
git submodule foreach git checkout master
git submodule foreach git pull Origin master
l'exécuter depuis votre module parent
Ajouter une option branch
dans .gitmodule
est NON lié au comportement détaché des sous-modules. Ce que @mkungla vous a dit est un non-sens.
De git submodule --help
, HEAD détaché est le comportement par défaut de git submodule update --remote
.
Tout d'abord, il y a pas besoin de spécifier une branche à suivre. Origin/master
est la branche par défaut à suivre.
--éloigné
Au lieu d'utiliser le SHA-1 enregistré du superprojet pour mettre à jour le sous-module, utilisez le statut de la branche de suivi à distance du sous-module. La télécommande utilisée est la télécommande de la branche (
branch.<name>.remote
), par défaut,Origin
. La branche distante utiliséemaster
par défaut.
Alors pourquoi HEAD est-il détaché après update
? Parce que le comportement par défaut de submodule.$name.update
est checkout
.
--check-out
Vérifiez la validation enregistrée dans le superprojet sur un HEAD détaché dans le sous-module. C'est le comportement par défaut, cette option est principalement utilisée pour remplacer
submodule.$name.update
lorsqu'il est défini sur une valeur autre quecheckout
.
Cela signifie que vous extrayez un ID de validation spécifique par défaut. De toute évidence, cela entraînera une tête isolée.
Si vous souhaitez que le sous-module soit fusionné automatiquement avec une branche distante, utilisez --merge
ou --rebase
.
--fusionner
Cette option est valide uniquement pour la mise à jour commande. Fusionnez la validation enregistrée dans le superprojet dans la branche actuelle du sous-module. Si cette option est donnée, le HEAD du sous-module ne sera pas détaché.
--rebase
Rebassez la branche actuelle sur la validation enregistrée dans le superprojet. Si cette option est donnée, le HEAD du sous-module ne sera pas détaché.
Tout ce que vous devez faire c'est
git submodule update --remote --merge
# or
git submodule update --remote --rebase
Il existe également une option permettant de définir --merge
ou --rebase
comme comportement par défaut de git submodule update
, en définissant submodule.$name.update
sur merge
ou rebase
.
Voici un exemple de configuration du comportement de mise à jour par défaut de la mise à jour de sous-module dans .gitmodule
.
[submodule "bash/plugins/dircolors-solarized"]
path = bash/plugins/dircolors-solarized
url = https://github.com/seebi/dircolors-solarized.git
update = merge # <-- this is what you need to add
Toute ma réponse est basée sur le manuel. git submodule --help
.
Découvrez ma réponse ici: Sous-modules Git: spécifiez une branche/un tag
Si vous le souhaitez, vous pouvez ajouter manuellement la ligne "branch = master" dans votre fichier .gitmodules. Lisez le lien pour voir ce que je veux dire.
EDIT: Pour suivre un projet de sous-module existant dans une branche, suivez les instructions de VonC ici:
L'autre façon de rendre votre sous-module pour vérifier la branche consiste à aller dans le fichier .gitmodules
dans le dossier racine et à ajouter le champ branch
dans la configuration du module comme suit:
branch = <branch-name-you-want-module-to-checkout>
Comme d'autres personnes l'ont dit, cela s'explique par le fait que le référent parent ne contient qu'une référence à (le SHA1 de) un commit spécifique dans le sous-module - il ne sait rien des branches. Cela devrait fonctionner ainsi: la branche qui était à cette validation peut avoir avancé (ou reculé), et si le référent parent avait référencé la branche, elle pourrait facilement casser lorsque cela se produirait.
Toutefois, en particulier si vous développez activement à la fois dans le référentiel parent et dans le sous-module, l'état detached HEAD
peut être déroutant et potentiellement dangereux. Si vous effectuez des commits dans le sous-module alors qu'il est dans l'état detached HEAD
, ils deviennent pendants et vous pouvez facilement perdre votre travail. (Les commits suspendus peuvent généralement être sauvés en utilisant git reflog
, mais il est bien préférable de les éviter en premier lieu.)
Si vous êtes comme moi, alors la plupart du temps , s'il y a une branche dans le sous-module qui pointe vers la validation en cours d'extraction, vous préféreriez vérifier cette branche plutôt que d'être détachée HEAD state à la même validation. Vous pouvez le faire en ajoutant l'alias suivant à votre fichier gitconfig
:
[alias]
submodule-checkout-branch = "!f() { git submodule -q foreach 'branch=$(git branch --no-column --format=\"%(refname:short)\" --points-at `git rev-parse HEAD` | grep -v \"HEAD detached\" | head -1); if [[ ! -z $branch && -z `git symbolic-ref --short -q HEAD` ]]; then git checkout -q \"$branch\"; fi'; }; f"
Maintenant, après avoir fait git submodule update
, il vous suffit d'appeler git submodule-checkout-branch
, et tout sous-module extrait lors d'une validation avec une branche pointant vers elle vérifiera cette branche. Si vous n'avez pas souvent plusieurs branches locales pointant toutes vers le même commit, cela fera généralement ce que vous voulez; sinon, au moins, cela garantira que tous les commits que vous faites fassent sur une branche réelle au lieu d'être laissés en suspens.
De plus, si vous avez configuré git pour mettre à jour automatiquement les sous-modules à la caisse (en utilisant git config --global submodule.recurse true
, voir cette réponse ), vous pouvez créer un point d'ancrage post-paiement qui appelle automatiquement cet alias:
$ cat .git/hooks/post-checkout
#!/bin/sh
git submodule-checkout-branch
Ensuite, vous n'avez pas besoin d'appeler ni git submodule update
ni git submodule-checkout-branch
, il vous suffit de faire git checkout
pour mettre à jour tous les sous-modules avec leurs commits respectifs et extraire les branches correspondantes (si elles existent).