215 votes

Pourquoi mon HEAD de sous-module Git est-il détaché de master ?

J'utilise des submodules Git. Après avoir extrait les modifications du serveur, il arrive souvent que la tête de mon submodule soit détachée de la branche principale.

Pourquoi cela se produit-il ?

Je dois toujours le faire :

git branch
git checkout master

Comment puis-je m'assurer que mon sous-module pointe toujours vers la branche master ?

189voto

Marko Points 151

EDIT :

Ver @Simba Réponse : pour une solution valable

submodule.<name>.update est ce que vous voulez changer, voir le docs - par défaut checkout
submodule.<name>.branch spécifier la branche distante à suivre - par défaut master


ANCIENNE RÉPONSE :

Personnellement, je déteste les réponses qui renvoient à des liens externes qui peuvent cesser de fonctionner au fil du temps. aquí (Sauf si la question est dupliquée) - dirigeant vers la question qui couvre le sujet entre les lignes d'un autre sujet, mais globalement égal : "Je ne réponds pas, lisez la documentation."

Donc, revenons à la question : Pourquoi cela arrive-t-il ?

Situation que vous avez décrite

Après avoir extrait les modifications du serveur, il arrive souvent que la tête de mon sous-module soit détachée de la branche principale.

C'est un cas courant lorsqu'on n'utilise pas sous-modules trop souvent ou vient de commencer avec sous-modules . Je crois que j'ai raison de dire, que nous tous ont été là à un moment donné où notre sous-module La tête de l'homme se détache.

  • Cause : Votre submodule ne suit pas la branche correcte (master par défaut).
    Solution : Assurez-vous que votre sous-module suit la bonne branche.

    $ 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>

  • Cause : Votre repo parent n'est pas configuré pour suivre la branche des submodules.
    Solution : Faites en sorte que votre submodule suive sa branche distante en ajoutant de nouveaux submodules avec les deux commandes suivantes.

    • Tout d'abord, vous indiquez à git de suivre votre télécommande <branch> .
    • vous dites à git d'effectuer une rebase ou une fusion au lieu d'un checkout
    • vous dites à git de mettre à jour votre sous-module à distance.

      $ git submodule add -b <branch> <repository> [<submodule-path>] $ git config -f .gitmodules submodule.<submodule-path>.update rebase $ git submodule update --remote

  • Si vous n'avez pas ajouté votre sous-module existant comme cela, vous pouvez facilement corriger cela :

    • Tout d'abord, vous devez vous assurer que votre sous-module a la branche contrôlée sur laquelle vous voulez être suivi.

      $ 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> $ git config -f .gitmodules submodule.<submodule-path>.update <rebase|merge>

Dans la plupart des cas, vous avez déjà corrigé votre DETACHED HEAD, car il était lié à l'un des problèmes de configuration ci-dessus.

fixation de la TÊTE DÉTACHÉE lorsque .update = checkout

$ 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 avez réussi à faire des modifications localement pour le sous-module et que vous les avez commitées et poussées vers le serveur distant, alors lorsque vous exécutez 'git checkout', Git vous en informe :

$ 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 de créer une branche temporaire peut être bonne, et ensuite vous pouvez simplement fusionner ces branches, etc. Cependant, personnellement, j'utiliserais simplement 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 qu'il existe d'autres cas où vous pouvez mettre vos submodules dans l'état DETACHED HEAD, j'espère que vous comprenez maintenant un peu mieux comment déboguer votre cas particulier.

138voto

Simba Points 2959

Desde git submodule --help , HEAD détaché est le comportement par défaut de git submodule update --remote . Cela n'a rien à voir avec la branche qui est suivie dans un sous-module.

Pour ceux qui ne veulent qu'une solution, passez directement à la 2ème partie.

Raison

Nous devons comprendre ce qu'est un sous-module.

Le sous-module est un moyen d'inclure un autre projet dans votre projet actuel. Il ne s'agit pas vraiment d'ajouter ces fichiers dans l'historique de commit de votre projet principal, mais en référençant un instantané (commit) du sous-module.

Citation de Commencer avec les sous-modules section du livre Pro Git

Bien que sbmodule DbConnector est un sous-répertoire de votre répertoire de travail, Git le voit comme un sous-module et ne suit pas son contenu lorsque vous n'êtes pas dans ce répertoire. A la place, Git le voit comme un un commit particulier de ce référentiel .

Chaque commit d'un repo est un instantané/état de votre code à ce moment-là. L'état du sous-module à ce moment-là doit être déterministe aussi. Vous ne pouvez pas dire que dans ce commit, j'inclus la branche master (ou autre) d'un autre repo. Vous devez spécifier l'état d'un sous-module par un id de commit .

Inclure un autre dépôt en tant que sous-module est essentiellement

git clone uri://another-repo path/to/submodule
cd path/to/submodule
git checkout <commit-id>

# git submodule system will add the reference commit id but not the files

Quand quelqu'un utilise votre repo avec un submodule, il clonera le submodule et checkout le commit spécifié aussi.

Et la vérification d'un commit résulte HEAD détaché. Pourquoi mon repo Git est-il entré dans un état HEAD détaché ?

Solution

Si vous voulez que le sous-module soit fusionné avec la branche distante automatiquement, utilisez --merge o --rebase .

man git-submodule

--merge

Cette option est uniquement valable pour la mise à jour commande. Fusionne le commit enregistré dans le superprojet dans la branche courante du sous-module. Si cette option est donnée, le HEAD du sous-module sera ne pas être détaché .

--rebase

Rebase la branche courante sur le commit enregistré dans le superprojet. Si cette option est donnée, le HEAD du sous-module sera ne pas être détaché .

Si votre sous-module a déjà été détaché, corrigez l'état détaché avant d'utiliser les deux solutions suivantes.

cd path/to/submodule
# Assuming you're tracking the 'master' in the submodule
git checkout master

Solution 1 : Utilisez les options dans la ligne de commande

# cd back to project root
git submodule update --remote --merge
# or
git submodule update --remote --rebase

Alias recommandés :

git config alias.supdate 'submodule update --remote --merge'

# do submodule update with
git supdate

Solution 2 : Ajouter des options dans le fichier de configuration

Une autre solution consiste à modifier le comportement de mise à jour du sous-module dans le fichier gitmodule par en fixant submodule.$name.update a merge o rebase . En gros, cela signifie que vous pouvez faire git submodule update --remote sans passer --merge o --rebase explcitly, mais lue depuis le fichier de configuration automatiquement.

Voici un exemple de la façon de configurer le comportement de mise à jour par défaut du submodule update en .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

Ou le configurer par la ligne de commande,

# replace $name with a real submodule name
git config -f .gitmodules submodule.$name.update merge

Autres

Ajout d'un branch option dans .gitmodule n'est PAS du tout liée au comportement détaché des submodules. L'ancienne réponse de mkungla est incorrecte, ou obsolète.

Disons clairement qu'il y a il n'est pas nécessaire de spécifier une branche à suivre . origin/master est la branche par défaut à suivre.

-- distant

Au lieu d'utiliser le SHA-1 enregistré du superprojet pour mettre à jour le sous-module, utilisez l'état de la branche de suivi à distance du sous-module. Le distant utilisé est le distant de la branche ( branch.<name>.remote ), par défaut origin . La branche distante utilisée est par défaut master .

Références

64voto

j2emanue Points 3456

J'en ai eu assez qu'il se détache toujours, alors j'utilise simplement un script shell script pour le construire pour tous mes modules. Je suppose que tous les submodules 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 à partir de votre module parent

13voto

Johnny Z Points 846

Consultez ma réponse ici : Sous-modules Git : Spécifier 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 plutôt les instructions de VonC ici :

Sous-modules Git : Spécifier une branche/un tag

8voto

frontendgirl Points 703

L'autre façon de faire en sorte que votre submodule vérifie la branche est d'aller dans la section .gitmodules dans le dossier Root et ajoutez le champ branch dans la configuration du module comme suit :

branch = <branch-name-you-want-module-to-checkout>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X