Pour le bénéfice du lecteur, ceci ici essaie de le résumer et de donner un guide étape par étape sur la façon de le faire si les choses ne fonctionnent pas comme prévu. Voici la manière testée et sûre pour les gitversions 2.17et supérieures de se débarrasser d'un sous-module :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Si cela ne fonctionne pas pour vous, voir ci-dessous.
- Aucune option. Rien de dangereux. Et n'envisagez même pas d'en faire plus!
- Testé avec Debian Buster
2.20.1et Ubuntu 18.04 2.17.1.
"$submodule" est juste de souligner où mettre le nom, et que vous devez faire attention aux espaces et autres
- Si sous Windows, ignorez la première ligne et remplacez
"$submodule"par la méthode Windows d'un chemin d'accès correctement spécifié au sous-module. (Je ne suis pas Windows)
Attention!
Ne touchez jamais vous-même l'intérieur du .gitrépertoire! Le montage à l'intérieur .gitentre dans le côté obscur. Restez à l'écart à tout prix!
Et oui, vous pouvez en être responsable git, car il manquait beaucoup de choses pratiques gitdans le passé. Comme une bonne façon de retirer à nouveau les sous-modules.
Je pense qu'il y a une partie très dangereuse dans la documentation de git submodule. Il recommande de $GIT_DIR/modules/<name>/vous retirer .
À ma connaissance, ce n'est pas seulement faux, c'est extrêmement dangereux et provoque des maux de tête majeurs à l'avenir! Voir ci-dessous.
Notez que
git module deinit
est l'inverse direct de
git module init
mais
git submodule deinit -- module
git rm -- module
est également tout à fait l'inverse de
git submodule add -- URL module
git submodule update --init --recursive -- module
parce que certaines commandes doivent faire plus que juste une seule chose:
git submodule deinit -- module
- (1) mises à jour
.git/config
git rm
- (2) supprime les fichiers du module
- (3) supprime ainsi récursivement les sous-modules du sous-module
- (4) mises à jour
.gitmodules
git submodule add
- tire dans les données
.git/modules/NAME/
- (1) le fait
git submodule init, donc les mises à jour.git/config
- (2) vérifie de
git submodule updatefaçon non récursive le module
- (4) mises à jour
.gitmodules
git submodule update --init --recursive -- module
- extrait d'autres données si nécessaire
- (3) vérifie récursivement les sous-modules du sous-module
Cela ne peut pas être entièrement symétrique, car le garder strictement symétrique n'a pas beaucoup de sens. Il n'y a tout simplement pas besoin de plus de deux commandes. «Extraire les données» est également implicite, car vous en avez besoin, mais la suppression des informations mises en cache n'est pas effectuée, car cela n'est pas du tout nécessaire et pourrait effacer des données précieuses.
C'est vraiment déroutant pour les nouveaux arrivants, mais c'est fondamentalement une bonne chose: fait gitsimplement ce qui est évident et le fait correctement, et n'essaie même pas d'en faire plus. gitest un outil qui doit faire un travail fiable, au lieu d'être juste un autre "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" se traduit pour moi par "une version maléfique d'un couteau suisse").
Je comprends donc les plaintes des gens, en disant "Pourquoi ne fait-il pas gitla chose évidente pour moi". En effet, «évident» dépend ici du point de vue. La fiabilité dans chaque situation est beaucoup plus importante. Par conséquent, ce qui est évident pour vous souvent n'est pas la bonne chose dans toutes les situations techniques possibles. N'oubliez pas que: l'AFAICS gitsuit la voie technique, pas la voie sociale. (D'où le nom intelligent: git)
Si cela échoue
Les commandes ci-dessus peuvent échouer en raison des éléments suivants:
- Tu
gites trop vieux. Utilisez ensuite un nouveau git. (Voir ci-dessous comment.)
- Vous avez des données non validées et risquez de perdre des données. Mieux vaut ensuite les engager en premier.
- Votre sous-module n'est pas propre dans un
git cleansens. Ensuite, nettoyez d'abord votre sous-module à l'aide de cette commande. (Voir ci-dessous.)
- Vous avez fait quelque chose dans le passé qui n'est pas soutenu par
git. Ensuite, vous êtes du côté obscur et les choses deviennent laides et compliquées. (Peut-être que l'utilisation d'une autre machine le corrige.)
- Il y a peut-être plus de façons d'échouer que je ne connais pas (je suis juste un grand
gitutilisateur).
Les correctifs possibles suivent.
Utilisez un nouveau git
Si votre machine est trop vieille, il n'y submodule deiniten a pas git. Si vous ne voulez pas (ou pouvez) mettre à jour votre git, alors utilisez simplement une autre machine avec une plus récente git! gitest censé être entièrement distribué, vous pouvez donc en utiliser un autre gitpour faire le travail:
workhorse:~/path/to/worktree$ git status --porcelain ne doit rien sortir! Si c'est le cas, nettoyez d'abord les choses!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Maintenant, fais le sous-module
othermachine:~/TMPWORK$ git commit . -m . && exit
workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD. Si cela ne fonctionne pas, utilisezgit reset --soft FETCH_HEAD
- Maintenant,
git statusnettoyez les choses, jusqu'à ce que ce soit à nouveau propre. Vous pouvez le faire, car vous l'avez déjà fait nettoyer, grâce à la première étape.
Cela othermachinepeut être une machine virtuelle ou un WSL Ubuntu sous Windows, peu importe. Même un chroot(mais je suppose que vous n'êtes pas root, car si vous l'êtes, rootil devrait être plus facile de mettre à jour vers le plus récent git).
Notez que si vous ne pouvez pas sshentrer, il existe de nombreuses façons de transporter les gitréférentiels. Vous pouvez copier votre arbre de travail sur une clé USB (y compris le .gitrépertoire) et cloner à partir de la clé. Clonez la copie, juste pour remettre les choses en ordre. Il peut s'agir d'un PITA, au cas où vos sous-modules ne seraient pas directement accessibles depuis une autre machine. Mais il existe également une solution:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Vous pouvez utiliser cette multiplication et celle-ci est enregistrée dans $HOME/.gitconfig. Quelque chose comme
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
réécrit les URL comme
https://github.com/XXX/YYY.git
dans
/mnt/usb/repo/XXX/YYY.git
C'est facile si vous commencez à vous habituer à des gitfonctionnalités puissantes comme celle-ci.
Nettoyer les choses d'abord
Le nettoyage manuel est bon, car de cette façon, vous pouvez peut-être détecter certaines choses que vous avez oubliées.
- Si git se plaint de choses non enregistrées, validez et poussez-le dans un endroit sûr.
- Si git se plaint de quelques restes
git statuset git clean -ixfdest votre ami
- Essayez de vous abstenir
rmet deinitaussi longtemps que vous le pouvez. Les options (comme -f) gitsont bonnes si vous êtes un pro. Mais comme vous êtes venu ici, vous n'êtes probablement pas aussi expérimenté dans la submodulerégion. Il vaut donc mieux être en sécurité que désolé.
Exemple:
$ git status --porcelain
M two
$ git submodule deinit two
error: the following file has local modifications:
two
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
$ cd two
$ git submodule deinit --all
error: the following file has local modifications:
md5chk
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
$ cd md5chk
$ git submodule deinit --all
error: the following file has local modifications:
tino
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
$ cd tino
$ git status --porcelain
?? NEW
$ git clean -i -f -d
Would remove the following item:
NEW
*** Commands ***
1: clean 2: filter by pattern 3: select by numbers 4: ask each
5: quit 6: help
What now> 1
Removing NEW
$ cd ../../..
$ git status --porcelain
$ git submodule deinit two
Cleared directory 'two'
Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'
Vous voyez, il n'y en a pas -fbesoin submodule deinit. Si les choses sont propres, dans un git cleansens. Notez également que ce git clean -xn'est pas nécessaire. Cela signifie qu'il git submodule deinitsupprime inconditionnellement les fichiers non suivis qui sont ignorés. C'est généralement ce que vous voulez, mais n'oubliez pas. Parfois, les fichiers ignorés peuvent être précieux, comme les données mises en cache qui nécessitent des heures ou des jours pour être calculées à nouveau.
Pourquoi ne jamais retirer $GIT_DIR/modules/<name>/?
Les gens veulent probablement supprimer le référentiel mis en cache, car ils ont peur de rencontrer un problème plus tard. C'est vrai, mais rencontrer ce «problème» est la bonne façon de le résoudre! Parce que la correction est facile et bien faite, vous pourrez vivre heureux pour toujours. Cela évite des problèmes plus encombrants que lorsque vous supprimez les données vous-même.
Exemple:
mkdir tmptest &&
cd tmptest &&
git init &&
git submodule add https://github.com/hilbix/empty.git two &&
git commit -m . &&
git submodule deinit two &&
git rm two &&
git commit -m . &&
git submodule add https://github.com/hilbix/src.git two
La dernière ligne génère l'erreur suivante:
A git directory for 'two' is found locally with remote(s):
origin https://github.com/hilbix/empty.git
If you want to reuse this local git directory instead of cloning again from
https://github.com/hilbix/src.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.
Pourquoi cette erreur? Parce que .git/modules/two/précédemment a été rempli à partir de https://github.com/hilbix/empty.git et doit maintenant être re-rempli à partir d'autre chose, à savoir https://github.com/hilbix/src.git . Vous ne le verrez pas si vous le re-remplissez depuis https://github.com/hilbix/empty.git
Que faire maintenant? Eh bien, faites exactement ce qui vous a été dit! Utilisation--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules ressemble alors
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/ donne
someunusedname/
two/
De cette façon, à l'avenir, vous pouvez changer de branche / valider en avant et en arrière et ne plus jamais avoir de problème , car vous aveztwo/ deux référentiels en amont différents (et éventuellement incompatibles). Et le meilleur est: vous conservez également les deux en cache localement.
- Ce n'est pas seulement vrai pour vous. Cela est également vrai pour tous les autres utilisateurs de votre référentiel.
- Et vous ne perdez pas l'histoire. Dans le cas où vous avez oublié de pousser la toute dernière version de l'ancien sous-module, vous pouvez entrer la copie locale et le faire plus tard. Notez qu'il est assez courant que quelqu'un oublie de pousser certains sous-modules (car il s'agit d'un PITA pour les nouveaux arrivants, jusqu'à ce qu'ils s'y habituent
git).
Cependant, si vous avez supprimé le répertoire mis en cache, les deux extractions différentes tomberont l'une sur l'autre, car vous n'utiliserez pas les --nameoptions, non? Ainsi, chaque fois que vous effectuez le paiement, vous devrez peut-être supprimer le .git/modules/<module>/répertoire encore et encore. Ceci est extrêmement lourd et rend difficile l'utilisation de quelque chose comme git bisect.
Il y a donc une raison très technique de conserver ce répertoire de module comme espace réservé. Les personnes qui recommandent de supprimer quelque chose ci-dessous .git/modules/ne savent pas mieux ou oublient de vous dire que cela rend les fonctionnalités puissantes comme git bisectpresque impossible à utiliser si cela croise une telle incompatibilité de sous-module.
Une autre raison est indiquée ci-dessus. Regardez le ls. Que voyez-vous là?
Eh bien, la 2ème variante de module two/n'est pas en dessous .git/modules/two/, elle est en dessous .git/modules/someunusedname/! Donc, des choses comme ça git rm $module; rm -f .git/module/$modulesont totalement fausses! Vous devez soit consulter, module/.gitsoit .gitmodulestrouver la bonne chose à supprimer!
Donc, non seulement la plupart des autres réponses tombent dans ce piège dangereux, même les gitextensions très populaires avaient ce bug ( il est maintenant corrigé là-bas )! Il vaut donc mieux garder les mains du .git/répertoire si vous ne le faites pas exactement, ce que vous faites!
Et du point de vue philosophique, essuyer l'histoire est toujours faux!
Sauf pour la mécanique quantique , comme d'habitude, mais c'est quelque chose de complètement différent.
Pour info vous l'avez probablement deviné: hilbix est mon compte GitHub.
git rm modulenameetrm -rf .git/modules/modulename