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 git
versions 2.17
et 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.1
et 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 .git
répertoire! Le montage à l'intérieur .git
entre 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 git
dans 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 update
faç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 git
simplement ce qui est évident et le fait correctement, et n'essaie même pas d'en faire plus. git
est 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 git
la 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 git
suit 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
git
es 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 clean
sens. 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
git
utilisateur).
Les correctifs possibles suivent.
Utilisez un nouveau git
Si votre machine est trop vieille, il n'y submodule deinit
en 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
! git
est censé être entièrement distribué, vous pouvez donc en utiliser un autre git
pour 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 status
nettoyez 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 othermachine
peut ê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, root
il devrait être plus facile de mettre à jour vers le plus récent git
).
Notez que si vous ne pouvez pas ssh
entrer, il existe de nombreuses façons de transporter les git
référentiels. Vous pouvez copier votre arbre de travail sur une clé USB (y compris le .git
ré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 git
fonctionnalité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 status
et git clean -ixfd
est votre ami
- Essayez de vous abstenir
rm
et deinit
aussi longtemps que vous le pouvez. Les options (comme -f
) git
sont bonnes si vous êtes un pro. Mais comme vous êtes venu ici, vous n'êtes probablement pas aussi expérimenté dans la submodule
ré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 -f
besoin submodule deinit
. Si les choses sont propres, dans un git clean
sens. Notez également que ce git clean -x
n'est pas nécessaire. Cela signifie qu'il git submodule deinit
supprime 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 --name
options, 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 bisect
presque 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/$module
sont totalement fausses! Vous devez soit consulter, module/.git
soit .gitmodules
trouver la bonne chose à supprimer!
Donc, non seulement la plupart des autres réponses tombent dans ce piège dangereux, même les git
extensions 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 modulename
etrm -rf .git/modules/modulename