Zum Nutzen des Lesers wird hier versucht, dies zusammenzufassen und eine schrittweise Anleitung zu geben, wie dies zu tun ist, wenn die Dinge nicht wie erwartet funktionieren. Im Folgenden finden Sie die getestete und sichere Methode für git
Versionen 2.17
und höher , um ein Submodul zu entfernen :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Wenn dies bei Ihnen nicht funktioniert, siehe unten.
- Keine Optionen. Nichts gefährliches. Und denken Sie nicht einmal daran, mehr zu tun!
- Getestet mit Debian Buster
2.20.1
und Ubuntu 18.042.17.1
.
"$submodule"
ist nur zu betonen, wo der Name zu setzen ist, und dass Sie mit Leerzeichen und dergleichen vorsichtig sein müssen
- Wenn unter Windows, ignorieren Sie die erste Zeile und ersetzen Sie
"$submodule"
einen ordnungsgemäß angegebenen Pfad zum Submodul durch die Windows-Methode. (Ich bin nicht Windows)
Warnung!
Berühren Sie niemals die Innenseiten des .git
Verzeichnisses selbst! Innen bearbeiten.git
betritt die dunkle Seite. Bleib um jeden Preis weg!
Und ja, Sie können dafür verantwortlich machen git
, da viele nützliche Dinge fehltengit
in der Vergangenheit . Wie ein richtiger Weg, um Submodule wieder zu entfernen.
Ich denke, es gibt einen sehr gefährlichen Teil in der Dokumentation von git submodule
. Es wird empfohlen, sich zu entfernen $GIT_DIR/modules/<name>/
.
Nach meinem Verständnis ist dies nicht nur einfach falsch, es ist äußerst gefährlich und verursacht in Zukunft große Kopfschmerzen! Siehe unten.
Beachten Sie, dass
git module deinit
ist die direkte Umkehrung zu
git module init
aber
git submodule deinit -- module
git rm -- module
ist auch ganz umgekehrt
git submodule add -- URL module
git submodule update --init --recursive -- module
weil einige Befehle im Grunde mehr als nur eine einzige Sache tun müssen:
git submodule deinit -- module
- (1) Aktualisierungen
.git/config
git rm
- (2) entfernt die Dateien des Moduls
- (3) entfernt dadurch rekursiv die Submodule des Submoduls
- (4) Aktualisierungen
.gitmodules
git submodule add
- zieht die Daten ein
.git/modules/NAME/
- (1) tut
git submodule init
, also Updates.git/config
- (2)
git submodule update
checkt das Modul also nicht rekursiv aus
- (4) Aktualisierungen
.gitmodules
git submodule update --init --recursive -- module
- zieht bei Bedarf weitere Daten ein
- (3) prüft die Submodule des Submoduls rekursiv
Dies kann nicht vollständig symmetrisch sein, da es wenig sinnvoll ist, es streng symmetrisch zu halten. Es sind einfach nicht mehr als zwei Befehle erforderlich. Auch das "Abrufen der Daten" ist implizit, da Sie es benötigen. Das Entfernen der zwischengespeicherten Informationen wird jedoch nicht durchgeführt, da dies überhaupt nicht erforderlich ist und möglicherweise wertvolle Daten löscht.
Für Neulinge ist das wirklich rätselhaft, aber im Grunde ist es eine gute Sache: macht git
einfach das Offensichtliche und macht das richtig und versucht nicht einmal mehr zu tun. git
ist ein Werkzeug, das einen zuverlässigen Job machen muss, anstatt nur eine andere "Eierlegende Wollmilchsau" zu sein ("Eierlegende Wollmilchsau" bedeutet für mich "eine böse Version eines Schweizer Taschenmessers").
Ich verstehe also Beschwerden von Menschen und sage: "Warum tut das nicht git
das Offensichtliche für mich?" Dies liegt daran, dass "offensichtlich" hier vom Standpunkt abhängt. Zuverlässigkeit in jeder Situation ist weitaus wichtiger. Daher ist das, was für Sie oft offensichtlich ist, nicht in allen möglichen technischen Situationen das Richtige. Bitte denken Sie daran: AFAICSgit
folgt dem technischen Weg, nicht dem sozialen. (Daher der kluge Name: git)
Wenn dies fehlschlägt
Die obigen Befehle können aus folgenden Gründen fehlschlagen:
- Dein
git
ist zu alt. Dann verwenden Sie eine neuere git
. (Siehe unten, wie es geht.)
- Sie haben nicht festgeschriebene Daten und können Daten verlieren. Dann legen Sie sie besser zuerst fest.
- Ihr Submodul ist in gewissem
git clean
Sinne nicht sauber . Reinigen Sie dann zuerst Ihr Submodul mit diesem Befehl. (Siehe unten.)
- Sie haben in der Vergangenheit etwas getan, das von nicht unterstützt wird
git
. Dann bist du auf der dunklen Seite und die Dinge werden hässlich und kompliziert. (Möglicherweise wird das Problem durch die Verwendung eines anderen Computers behoben.)
- Vielleicht gibt es noch mehr Möglichkeiten zum Scheitern, die mir nicht bekannt sind (ich bin nur ein
git
Power-User).
Mögliche Korrekturen folgen.
Verwenden Sie eine neuere git
Wenn Ihre Maschine zu alt ist, ist keine submodule deinit
in Ihrer git
. Wenn Sie Ihre nicht aktualisieren möchten (oder können), verwenden Sie git
einfach eine andere Maschine mit einer neueren git
! git
soll vollständig verteilt sein, sodass Sie einen anderen verwenden können git
, um die Arbeit zu erledigen:
workhorse:~/path/to/worktree$ git status --porcelain
darf nichts ausgeben! Wenn ja, bereinigen Sie zuerst die Dinge!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Jetzt mach das Submodul-Zeug
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
. Wenn dies nicht funktioniert, verwenden Siegit reset --soft FETCH_HEAD
- Jetzt bereinige Dinge, bis
git status
es wieder sauber ist. Sie können dies tun, weil Sie es dank des ersten Schritts schon einmal sauber hatten.
Dies othermachine
kann eine VM oder eine Ubuntu-WSL unter Windows sein. Sogar a chroot
(aber ich gehe davon aus, dass Sie kein Root sind, denn wenn Sie es sind root
, sollte es einfacher sein, auf das neuere zu aktualisieren git
).
Beachten Sie ssh
, dass es zahlreiche Möglichkeiten zum Transport von git
Repositorys gibt , wenn Sie nicht einsteigen können . Sie können Ihren Arbeitsbaum auf einen USB-Stick (einschließlich des .git
Verzeichnisses) kopieren und vom Stick klonen. Klonen Sie die Kopie, um die Dinge wieder sauber zu machen. Dies kann eine PITA sein, falls Ihre Submodule nicht direkt von einer anderen Maschine aus zugänglich sind. Aber auch dafür gibt es eine Lösung:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Sie können diese Multiplikation verwenden, und diese wird in gespeichert $HOME/.gitconfig
. Etwas wie
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
schreibt URLs wie neu
https://github.com/XXX/YYY.git
in
/mnt/usb/repo/XXX/YYY.git
Es ist einfach, wenn Sie sich an leistungsstarke git
Funktionen wie diese gewöhnen .
Bereinigen Sie die Dinge zuerst
Die manuelle Reinigung ist gut, da Sie auf diese Weise möglicherweise einige Dinge erkennen, die Sie vergessen haben.
- Wenn sich git über nicht gespeicherte Sachen beschwert, legen Sie sie fest und schieben Sie sie an einen sicheren Ort.
- Wenn git sich über einige Reste beschwert,
git status
undgit clean -ixfd
dein Freund ist
- Versuchen Sie eine der Optionen zu verzichten
rm
und deinit
so lange wie möglich. Optionen (wie -f
) für git
sind gut, wenn Sie ein Profi sind. Aber als Sie hierher kamen, sind Sie wahrscheinlich nicht so erfahren in der submodule
Gegend. Also besser auf Nummer sicher gehen.
Beispiel:
$ 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'
Sie sehen, es wird nicht -f
benötigt submodule deinit
. Wenn die Dinge in gewissem git clean
Sinne sauber sind . Beachten Sie auch, dass dies git clean -x
nicht benötigt wird. Dies bedeutet, dass git submodule deinit
nicht verfolgte Dateien, die ignoriert werden , bedingungslos entfernt werden. Dies ist normalerweise das, was Sie wollen, aber vergessen Sie es nicht. Manchmal sind ignorierte Dateien wertvoll, z. B. zwischengespeicherte Daten, deren erneute Berechnung Stunden bis Tage dauert.
Warum nie entfernen $GIT_DIR/modules/<name>/
?
Wahrscheinlich möchten Benutzer das zwischengespeicherte Repository entfernen, weil sie Angst haben, später auf ein Problem zu stoßen. Dies ist wahr, aber auf dieses "Problem" zu stoßen, ist der richtige Weg, es zu lösen! Weil die Lösung einfach ist und richtig gemacht wird, können Sie glücklich leben. Dies vermeidet umständlichere Probleme als wenn Sie die Daten selbst entfernen.
Beispiel:
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
Die letzte Zeile gibt folgenden Fehler aus:
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.
Warum dieser Fehler? Weil .git/modules/two/
zuvor von https://github.com/hilbix/empty.git ausgefüllt wurde und jetzt von etwas anderem neu ausgefüllt werden soll, nämlich https://github.com/hilbix/src.git . Sie werden dies nicht sehen, wenn Sie es erneut von https://github.com/hilbix/empty.git ausfüllen
Was nun? Nun, mach genau das, was dir gesagt wurde! Verwenden--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules
dann sieht es so aus
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/
gibt
someunusedname/
two/
Auf diese Weise können Sie in Zukunft Zweige / Commit vorwärts und rückwärts wechseln und werden nie wieder in Schwierigkeiten geraten, two/
da zwei verschiedene (und möglicherweise inkompatible) Upstream-Repositorys vorhanden sind. Und das Beste ist: Sie behalten beide auch lokal zwischengespeichert.
- Dies gilt nicht nur für Sie. Dies gilt auch für alle anderen Benutzer Ihres Repositorys.
- Und Sie verlieren nicht die Geschichte. Falls Sie vergessen haben, die neueste Version des alten Submoduls zu pushen, können Sie die lokale Kopie eingeben und dies später tun. Beachten Sie, dass es häufig vorkommt, dass jemand vergisst, einige Submodule zu pushen (da dies eine PITA für Neulinge ist, bis sie sich daran gewöhnt haben
git
).
Wenn Sie jedoch das zwischengespeicherte Verzeichnis entfernt haben, stoßen beide unterschiedlichen Kassen aufeinander, da Sie die --name
Optionen nicht verwenden , oder? Jedes Mal, wenn Sie zur Kasse gehen, müssen Sie das .git/modules/<module>/
Verzeichnis möglicherweise immer wieder entfernen . Dies ist äußerst umständlich und macht es schwierig, so etwas zu verwenden git bisect
.
Es gibt also einen sehr technischen Grund, dieses Modulverzeichnis als Platzhalter beizubehalten. Leute, die empfehlen, etwas unten zu entfernen, .git/modules/
wissen es entweder nicht besser oder vergessen zu sagen, dass dies leistungsstarke Funktionen wie git bisect
nahezu unmöglich macht, wenn dies eine solche Inkompatibilität mit Submodulen überschreitet.
Ein weiterer Grund ist oben gezeigt. Schau dir das an ls
. Was siehst du dort?
Nun, die 2. Variante des Moduls two/
ist nicht unter .git/modules/two/
, es ist unter .git/modules/someunusedname/
! Also sind Dinge wie git rm $module; rm -f .git/module/$module
völlig falsch! Sie müssen entweder konsultieren module/.git
oder .gitmodules
das Richtige zum Entfernen finden!
So fallen nicht nur die meisten anderen Antworten in diese gefährliche Falle, auch sehr beliebte git
Erweiterungen hatten diesen Fehler ( er ist jetzt dort behoben )! Behalten Sie also besser das .git/
Verzeichnis in der Hand, wenn Sie nicht genau wissen, was Sie tun!
Und aus philosophischer Sicht ist das Löschen der Geschichte immer falsch!
Abgesehen von der Quantenmechanik , wie üblich, aber das ist etwas völlig anderes.
Zu Ihrer Information, Sie haben es wahrscheinlich erraten: hilbix ist mein GitHub-Account.
git rm modulename
undrm -rf .git/modules/modulename