Comment déplacer un sous-module Git existant dans un référentiel Git?

356

Je voudrais changer le nom de répertoire d'un sous-module Git dans mon superprojet Git.

Supposons que j'ai l'entrée suivante dans mon .gitmodulesfichier:

[submodule ".emacs.d/vimpulse"]  
path = .emacs.d/vimpulse  
url = git://gitorious.org/vimpulse/vimpulse.git

Que dois-je taper pour déplacer le .emacs.d/vimpulserépertoire .emacs.d/vendor/vimpulsesans le supprimer d'abord (expliqué ici et ici ), puis l'ajouter à nouveau.

Est-ce que Git a vraiment besoin de tout le chemin dans la balise de sous-module

[submodule ".emacs.d/vimpulse"]

ou est-il également possible de stocker uniquement le nom du sous-projet?

[submodule "vimpulse"]
chahut
la source
REMARQUE: l'OP répond à sa propre question avec la git mvcommande, directement dans la question.
Dan Rosenstark
CEPENDANT, vous ne pouvez pas utiliser git mvcomme ça. Utilisez deinitensuite rm comme stackoverflow.com/a/18892438/8047 spécifié .
Dan Rosenstark
14
@Yar: au moins sur git 2.0.0, git mv fonctionne aussi pour les sous-modules, pas besoin d'autre chose.
Pedro Romano
9
Commencer avec Git pour 1.8.5déplacer des sous-modules est pris en charge de manière native à l'aide de la git mvcommande (à partir des notes de version , d'abord liées par @thisch lui-même). Également répondu ici
dennisschagt
git mvdéplace le sous-module dans l'espace de travail et met correctement à jour les fichiers .git du sous-module, mais le sous-dossier du dossier .git / modules du référentiel parent reste le même - est-ce correct? (J'utilise git 2.19.0 sous Windows)
yoyo

Réponses:

377

Remarque: Comme mentionné dans les commentaires, cette réponse fait référence aux étapes nécessaires avec les anciennes versions de git. Git a maintenant un support natif pour déplacer des sous-modules:

Depuis git 1.8.5, git mv old/submod new/submodfonctionne comme prévu et fait toute la plomberie pour vous. Vous voudrez peut-être utiliser git 1.9.3 ou plus récent, car il comprend des correctifs pour le déplacement des sous-modules.


Le processus est similaire à la façon dont vous supprimeriez un sous-module (voir Comment supprimer un sous-module? ):

  1. Modifiez .gitmoduleset modifiez le chemin du sous-module de manière appropriée et placez-le dans l'index avec git add .gitmodules.
  2. Si nécessaire, créez le répertoire parent du nouvel emplacement du sous-module ( mkdir -p new/parent).
  3. Déplacer tout le contenu de l'ancien vers le nouveau répertoire ( mv -vi old/parent/submodule new/parent/submodule).
  4. Assurez-vous que Git suit ce répertoire ( git add new/parent).
  5. Supprimez l'ancien répertoire avec git rm --cached old/parent/submodule.
  6. Déplacez le répertoire .git/modules/old/parent/submoduleavec tout son contenu vers .git/modules/new/parent/submodule.
  7. Modifiez le .git/modules/new/parent/configfichier, assurez-vous que l'élément de l'arbre de travail pointe vers les nouveaux emplacements, donc dans cet exemple, il devrait l'être worktree = ../../../../../new/parent/module. En général, il doit y avoir deux ..répertoires de plus dans le chemin direct à cet endroit.
  8. Modifiez le fichier new/parent/module/.git, assurez-vous que le chemin d'accès pointe vers le nouvel emplacement correct dans le .gitdossier principal du projet , donc dans cet exemple gitdir: ../../../.git/modules/new/parent/submodule.

    git status la sortie ressemble à ceci pour moi après:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Enfin, validez les modifications.

Axel Beckert
la source
37
Lorsque vous mettez à jour .gitmodules, assurez-vous de mettre à jour à la fois cette pathconfiguration et le nom du sous-module. Par exemple, en déplaçant foo / module vers bar / module, vous devez changer dans .gitmodules la section [submodule "foo/module"]en [submodule "bar/module"], et sous cette même section path = foo/moduleen path = bar/module. Vous devez également modifier dans .git / config la section [submodule "foo/module"]en [submodule "bar/module"].
wilhelmtell
3
Cela n'a pas fonctionné pour moi non plus ... la solution la plus proche que j'ai trouvée est de supprimer un sous-module (une douleur), puis de le rajouter à différents endroits.
Pablo Olmos de Aguilera C.
33
Une note très très importante: si vous obtenez fatal: 'git status --porcelain' failed in...simplement supprimer tous les fichiers ou répertoires .git dans le sous-module.
antitoxique
19
Il semble que ce message manque quelques étapes, telles que l'édition .git/modules/old/parent/submodule, le déplacement vers le nouvel emplacement, la mise gitdirà jour dans old/parent/submodule/.git...
szx
38
Depuis git 1.8.5, git mv old/submod new/submodfonctionne comme prévu et fait toute la plomberie pour vous. Vous voudrez probablement utiliser git 1.9.3+ car il inclut des correctifs pour le déplacement des sous-modules.
Valloric
232

La réponse la plus moderne, tirée du commentaire de Valloric ci-dessus:

  1. Mettre à niveau vers Git 1.9.3 (ou 2.18 si le sous-module contient des sous-modules imbriqués )
  2. git mv old/submod new/submod
  3. Ensuite, le .gitmodules et le répertoire du sous-module sont déjà organisés pour une validation (vous pouvez le vérifier avec git status.)
  4. Engagez les changements avec git commitet vous êtes prêt à partir!

Terminé!

phatmann
la source
3
Cela a en effet fonctionné 1.9.3 sauf pour un sous-module à l'intérieur du sous-module déplacé. Cela nécessitait un nettoyage manuel.
Pascal
3
Cela devrait déjà fonctionner en version 1.8.5comme décrit dans les notes de version .
dennisschagt
6
Cette réponse devrait obtenir 1000 votes positifs, j'ai presque fait un gâchis avec mon dépôt en faisant les étapes décrites ci-dessus, vraiment StackOverflow devrait avoir un cas d'utilisation pour cette situation.
MGP
5
Wow, cela a fonctionné comme un charme (git 1.9.5), je souhaite que ce soit la réponse choisie.
Alex Ilyaev
7
Une chose que cela ne fait pas, c'est qu'elle ne modifie pas l'étiquette initiale du sous-module. Si vous vérifiez le .gitmodulesfichier, le old/submodest toujours utilisé comme étiquette pour le sous-module alors que le chemin a été modifié. Pour que l'étiquette change également, il semble que vous devez réellement déplacer le chemin du répertoire des modules à l'intérieur .git, puis changer manuellement l'étiquette .gitmodules.
CMCDragonkai
55

Dans mon cas, je voulais déplacer un sous-module d'un répertoire dans un sous-répertoire, par exemple "AFNetworking" -> "ext / AFNetworking". Voici les étapes que j'ai suivies:

  1. Modifiez .gitmodules en changeant le nom et le chemin du sous-module en "ext / AFNetworking"
  2. Déplacer le répertoire git du sous-module de ".git / modules / AFNetworking" vers ".git / modules / ext / AFNetworking"
  3. Déplacer la bibliothèque de "AFNetworking" vers "ext / AFNetworking"
  4. Modifiez ".git / modules / ext / AFNetworking / config" et corrigez la [core] worktreeligne. Le mien est passé de ../../../AFNetworkingà../../../../ext/AFNetworking
  5. Modifiez "ext / AFNetworking / .git" et corrigez gitdir. Le mien est passé de ../.git/modules/AFNetworkingà../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Enfin, j'ai vu dans le statut git:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

Et voilà. L'exemple ci-dessus ne change pas la profondeur du répertoire, ce qui fait une grande différence dans la complexité de la tâche, et ne change pas le nom du sous-module (ce qui n'est peut-être pas vraiment nécessaire, mais je l'ai fait pour être cohérent avec ce se produirait si j'ajoutais un nouveau module sur ce chemin.)

Matt Connolly
la source
4
Merci Matt. J'étais perdu sur la réponse acceptée. Merci d'avoir couvert plus que le cas de base. Cela a fonctionné comme un charme.
Andrew Hubbs
Vous n'avez pas besoin de parcourir les chemins .git / modules ou de changer le nom du sous-module (comme le mentionnent arand et Bob Bell). Cependant, cela peut garder les choses plus propres.
gatoatigrado
N'oubliez pas d'effectuer les étapes 2, 3, 4 et 5 de manière récursive pour tous les sous-sous-modules.
herzbube
22

[Mise à jour: 2014-11-26] Comme Yar le résume bien ci-dessous, avant de faire quoi que ce soit, assurez-vous de connaître l'URL du sous-module. Si inconnue, ouvrez .git/.gitmoduleset examinez la clé submodule.<name>.url.

Ce qui a fonctionné pour moi a été de supprimer l'ancien sous-module en utilisant git submodule deinit <submodule>suivi de git rm <submodule-folder>. Ajoutez ensuite le sous-module avec le nouveau nom de dossier et validez. La vérification de l'état de git avant de valider affiche l'ancien sous-module renommé avec le nouveau nom et le .gitmodule modifié.

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"
Mark Mikofski
la source
1
Cela nécessite git 1.8.3 ou supérieur. Voir cet article pour mettre à jour votre git: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole
1
Ou, une meilleure façon: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole
@MichaelCole Merci! Tu as raison! Voir les notes de publication de Git-1.8.3 . Pour info: Ubuntu-13.10 (Saucy Salamander) a Git-1.8.3.2 , mais bon de savoir qu'il y a ppa . En outre, la stratégie de fusion des sous- arbres git à mon humble avis est une meilleure approche; J'ai abandonné les sous-modules pour mes propres projets. Encore bon à comprendre pour les projets existants.
Mark Mikofski
J'ai essayé plusieurs solutions mais la vôtre est la meilleure. Utilisez uniquement la ligne de commande pour ne pas avoir (et ne devriez pas) modifier un fichier git. Merci!
nahung89
12

L'astuce semble être de comprendre que le .gitrépertoire des sous-modules est maintenant conservé dans le référentiel maître, sous .git/modules, et chaque sous-module a un .gitfichier qui le pointe. Voici la procédure dont vous avez besoin maintenant:

  • Déplacez le sous-module dans sa nouvelle maison.
  • Modifiez le .gitfichier dans le répertoire de travail du sous-module et modifiez le chemin qu'il contient afin qu'il pointe vers le bon répertoire dans le répertoire du référentiel maître .git/modules.
  • Entrez dans le répertoire du référentiel maître .git/moduleset recherchez le répertoire correspondant à votre sous-module.
  • Modifiez le configfichier, en mettant à jour le worktreechemin afin qu'il pointe vers le nouvel emplacement du répertoire de travail du sous-module.
  • Modifiez le .gitmodulesfichier à la racine du référentiel maître, en mettant à jour le chemin d'accès au répertoire de travail du sous-module.
  • git add -u
  • git add <parent-of-new-submodule-directory>(Il est important que vous ajoutiez le parent et non le répertoire du sous-module lui-même.)

Quelques notes:

  • Les [submodule "submodule-name"]lignes .gitmoduleset .git/configdoivent correspondre, mais ne correspondent à rien d'autre.
  • Le répertoire de travail du sous-module et le .gitrépertoire doivent pointer correctement l'un vers l'autre.
  • Les fichiers .gitmoduleset .git/configdoivent être synchronisés.
Paul Gideon Dann
la source
9

La chaîne entre guillemets après "[sous-module" n'a pas d'importance. Vous pouvez le changer en "foobar" si vous le souhaitez. Il est utilisé pour trouver l'entrée correspondante dans ".git / config".

Par conséquent, si vous effectuez la modification avant d'exécuter "git submodule init", cela fonctionnera correctement. Si vous apportez la modification (ou la récupérez via une fusion), vous devrez soit éditer manuellement .git / config, soit réexécuter "git submodule init". Si vous faites ce dernier, vous vous retrouverez avec une entrée "échouée" inoffensive avec l'ancien nom dans .git / config.

Bob Bell
la source
C'est vraiment ennuyeux, mais vous avez raison. Le pire, c'est que si vous changez simplement l'URL, l'exécution de git init ne semble pas la mettre à jour, vous devez éditer manuellement .git / config.
crimson_penguin
1
dans ce cas git submodule syncpropage .git/configautomatiquement le changement
CharlesB
9

Vous pouvez simplement ajouter un nouveau sous-module et supprimer l'ancien sous-module à l'aide de commandes standard. (devrait éviter toute erreur accidentelle à l'intérieur de .git)

Exemple de configuration:

mkdir foo; cd foo; git init; 
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

Examinez le déplacement de «jquery» vers «vendor / jquery / jquery»:

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`

## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"

## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)

## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

Méthode bonus pour les grands sous-modules:

Si le sous-module est volumineux et que vous préférez ne pas attendre le clone, vous pouvez créer le nouveau sous-module en utilisant l'ancien comme origine, puis changer d'origine.

Exemple (utilisez le même exemple de configuration)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`

# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"

## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"

## remove old submodule
...
Lance Rushing
la source
Si vous n'utilisez pas head, vous devrez peut-être également consulter la version correcte du module à l'adresse newPath.
paulmelnikow
2

La solution donnée n'a pas fonctionné pour moi, mais une version similaire a fonctionné ...

C'est avec un référentiel cloné, donc les sous-modules git repos sont contenus dans les répertoires supérieurs .git dir. Tous les cations proviennent du référentiel supérieur:

  1. Modifiez .gitmodules et modifiez le paramètre "path =" du sous-module en question. (Pas besoin de changer l'étiquette, ni d'ajouter ce fichier à l'index.)

  2. Modifiez .git / modules / name / config et modifiez le paramètre "worktree =" pour le sous-module en question

  3. courir:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

Je me demande si cela fait une différence si les référentiels sont atomiques, ou des sous-modules relatifs, dans mon cas c'était relatif (sous-module / .git est une référence à topproject / .git / modules / submodule)

arand
la source
2

Utilisez simplement le script shell git-submodule-move .

Flimm
la source
Heh, j'ai relu cette question, et utilisé l'une des réponses les plus votées, et maintenant je souhaite que j'aie fait défiler vers le bas et vu ma réponse précédente que j'avais oubliée.
Flimm
2

Je viens de traverser cette épreuve hier et cette réponse a parfaitement fonctionné. Voici mes étapes, pour plus de clarté:

  1. Assurez-vous que le sous-module est archivé et envoyé à son serveur. Vous devez également savoir sur quelle branche son est activée.
  2. Vous avez besoin de l'URL de votre sous-module! À utiliser more .gitmodulescar une fois le sous-module supprimé, il ne sera plus là
  3. Vous pouvez maintenant utiliser deinit, rmpuissubmodule add

EXEMPLE

COMMANDES

    git submodule deinit Classes/lib/mustIReally
    git rm foo
    git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus

    # do your normal commit and push
    git commit -a 

REMARQUE: git mv ne fait pas cela. Du tout.

Dan Rosenstark
la source
3
Bon résumé. +1 git mvdevrait cependant être meilleur dans les toutes dernières versions de Git.
VonC
@VonC J'ai testé sur git 1.8.5, presque sûr que c'est à peu près aussi bon que possible mv. Merci!
Dan Rosenstark