A beneficio del lettore, questo qui cerca di riassumere e fornire una guida passo-passo su come farlo se le cose non funzionano come previsto. Di seguito è riportato il modo testato e sicuro per la gitversione 2.17e successive per sbarazzarsi di un sottomodulo :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Se questo non funziona per te, vedi sotto.
- Nessuna opzione Niente di pericoloso. E non considerare nemmeno di fare di più!
- Testato con Debian Buster
2.20.1e Ubuntu 18.04 2.17.1.
"$submodule" è solo per sottolineare dove mettere il nome e che devi stare attento con spazi e simili
- Se su Windows ignora la prima riga e sostituisci
"$submodule"con il modo Windows di un percorso correttamente specificato al sottomodulo. (Non sono Windows)
Avvertimento!
Non toccare mai l'interno della .gitdirectory da soli! La modifica all'interno .gitentra nel lato oscuro. Stai lontano a tutti i costi!
E sì, puoi dare la colpa gita questo, dato che molte cose utili mancavano in gitpassato. Come un modo corretto per rimuovere nuovamente i sottomoduli.
Penso che ci sia una parte molto pericolosa nella documentazione di git submodule. Si consiglia di rimuovere $GIT_DIR/modules/<name>/te stesso.
Secondo me questo non è solo un errore, ma è estremamente pericoloso e provoca in futuro grossi mal di testa! Vedi sotto.
Nota che
git module deinit
è l'inverso diretto a
git module init
ma
git submodule deinit -- module
git rm -- module
inoltre è abbastanza il contrario
git submodule add -- URL module
git submodule update --init --recursive -- module
perché alcuni comandi in pratica devono fare più di una sola cosa:
git submodule deinit -- module
- (1) aggiornamenti
.git/config
git rm
- (2) rimuove i file del modulo
- (3) rimuove in tal modo ricorsivamente i sottomoduli del sottomodulo
- (4) aggiornamenti
.gitmodules
git submodule add
- inserisce i dati in
.git/modules/NAME/
- (1)
git submodule initsì, quindi aggiorna.git/config
- (2)
git submodule update, quindi, controlla in modo non ricorsivo il modulo
- (4) aggiornamenti
.gitmodules
git submodule update --init --recursive -- module
- inserisce ulteriori dati se necessario
- (3) verifica ricorsivamente i sottomoduli del sottomodulo
Questo non può essere completamente simmetrico, poiché mantenerlo rigorosamente simmetrico non ha molto senso. Semplicemente non sono necessari più di due comandi. Anche "estrarre i dati" è implicito, perché ne hai bisogno, ma non è possibile rimuovere le informazioni memorizzate nella cache, perché non sono affatto necessarie e potrebbero cancellare dati preziosi.
Questo è davvero sconcertante per i nuovi arrivati, ma fondamentalmente è una buona cosa: gitfa semplicemente la cosa ovviamente e fa bene, e non cerca nemmeno di fare di più. gitè uno strumento che deve fare un lavoro affidabile, invece di essere solo un altro "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" si traduce per me in "una versione malvagia di un coltellino svizzero").
Quindi capisco le lamentele delle persone, dicendo "Perché non fa gitla cosa ovvia per me". Questo perché "ovvio" qui dipende dal punto di vista. L'affidabilità in ogni situazione è molto più importante. Quindi ciò che è ovvio per te spesso non è la cosa giusta in tutte le possibili situazioni tecniche. Ricorda che: AFAICS gitsegue il percorso tecnico, non quello sociale. (Da qui il nome intelligente: git)
Se questo fallisce
I comandi precedenti potrebbero non riuscire a causa di:
- Sei
gittroppo vecchio. Quindi utilizzare un nuovogit . (Vedi sotto come.)
- Hai dati non impegnati e potresti perdere dati. Quindi meglio impegnarli prima.
- Il tuo sottomodulo non è pulito in a
git clean certo senso. Quindi prima pulisci il tuo sottomodulo usando quel comando. (Vedi sotto.)
- In passato hai fatto qualcosa che non è supportato da
git . Allora sei sul lato oscuro e le cose si fanno brutte e complicate. (Forse usando un'altra macchina lo risolve.)
- Forse ci sono altri modi per fallire di cui non sono a conoscenza (sono solo un po 'di
gitpower-user.)
Seguono possibili correzioni.
Usa un nuovo git
Se la tua macchina è troppo vecchia non ce n'è submodule deinitnella tua git. Se non vuoi (o puoi) aggiornare il tuo git, usa semplicemente un'altra macchina con una nuova git! gitè pensato per essere completamente distribuito, quindi puoi usarne un altro gitper completare il lavoro:
workhorse:~/path/to/worktree$ git status --porcelain non deve emettere nulla! In tal caso, prima pulisci le cose!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Ora fai le cose del sottomodulo
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. Se questo non funziona, utilizzaregit reset --soft FETCH_HEAD
- Ora
git statuspulisci le cose, fino a quando non è di nuovo pulito. Sei in grado di farlo, perché l'hai già pulito prima, grazie al primo passo.
Questo othermachinepuò essere un po 'di VM, o qualche Ubuntu WSL in ambiente Windows, a prescindere. Anche un chroot(ma presumo che tu non sia root, perché se lo sei rootdovrebbe essere più facile aggiornarlo al più recente git).
Nota che se non riesci ssha entrare, ci sono un sacco di modi per trasportare i gitrepository. Puoi copiare il tuo worktree su una chiavetta USB (compresa la .gitdirectory) e clonarlo dalla chiavetta. Clona la copia, solo per riportare le cose in modo pulito. Questo potrebbe essere un PITA, nel caso in cui i sottomoduli non siano accessibili direttamente da altre macchine. Ma c'è anche una soluzione per questo:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
È possibile utilizzare questo moltiplicare e questo viene salvato in $HOME/.gitconfig. Qualcosa di simile a
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
riscrive URL come
https://github.com/XXX/YYY.git
in
/mnt/usb/repo/XXX/YYY.git
È facile se inizi ad abituarti a potenti gitfunzionalità come questa.
Pulisci prima le cose
La pulizia manuale è buona, perché in questo modo potresti forse rilevare alcune cose che hai dimenticato.
- Se git si lamenta di cose non salvate, commetti e spingile in un posto sicuro.
- Se git si lamenta di alcuni avanzi
git statused git clean -ixfdè tuo amico
- Cerca di astenersi dalle opzioni per
rme il deinitpiù a lungo possibile. Le opzioni (come -f) per gitsono buone se sei un professionista. Ma come sei venuto qui, probabilmente non sei così esperto nella submodulezona. Quindi meglio prevenire che curare.
Esempio:
$ 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'
Vedi, non ce n'è -fbisogno submodule deinit. Se le cose sono pulite, in un git cleancerto senso. Si noti inoltre che git clean -xnon è necessario. Ciò significa che git submodule deinitrimuove incondizionatamente i file non monitorati che vengono ignorati. Questo è di solito quello che vuoi, ma non dimenticartene. A volte i file ignorati possono essere preziosi, come i dati memorizzati nella cache che richiedono ore o giorni per essere nuovamente calcolati.
Perché non rimuoverlo mai $GIT_DIR/modules/<name>/?
Probabilmente le persone vogliono rimuovere il repository memorizzato nella cache, perché hanno paura di incorrere in un problema in seguito. Questo è vero, ma imbattersi in quel "problema" è il modo corretto di risolverlo! Perché la correzione è facile e fatta bene sarai in grado di vivere per sempre felici e contenti. Ciò evita problemi più ingombranti rispetto a quando si rimuovono i dati da soli.
Esempio:
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
L'ultima riga genera il seguente errore:
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.
Perché questo errore? Perché in .git/modules/two/precedenza era popolato da https://github.com/hilbix/empty.git e ora deve essere ripopolato da qualcos'altro, vale a dire https://github.com/hilbix/src.git . Non lo vedrai se lo popoli nuovamente da https://github.com/hilbix/empty.git
Cosa fare adesso? Bene, fai esattamente come detto! Uso--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules allora sembra
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/ dà
someunusedname/
two/
In questo modo in futuro puoi cambiare succursale / impegnarti in avanti e indietro e non avrai mai più problemi , a causa di two/due diversi repository (e forse incompatibili) a monte. E il migliore è: tieni anche entrambi memorizzati nella cache locale.
- Questo non è vero solo per te. È anche vero per tutti gli altri che usano il tuo repository.
- E non perdi la storia. Nel caso in cui ti sei dimenticato di inviare l'ultima versione del vecchio sottomodulo, puoi inserire la copia locale e farlo in seguito. Si noti che è abbastanza comune che qualcuno si dimentichi di inviare alcuni sottomoduli (perché questa è una PITA per i nuovi arrivati, fino a quando non si sono abituati
git).
Tuttavia, se hai rimosso la directory memorizzata nella cache, entrambi i diversi checkout si imbatteranno l'uno nell'altro, perché non utilizzerai le --nameopzioni, giusto? Quindi ogni volta che fai il checkout forse devi rimuovere la .git/modules/<module>/directory ancora e ancora. Questo è estremamente ingombrante e rende difficile usare qualcosa del genere git bisect.
Quindi c'è un motivo molto tecnico per mantenere questa directory del modulo come segnaposto. Le persone che raccomandano di rimuovere qualcosa di seguito .git/modules/o non sanno meglio o dimenticano di dirti che questo rende potenti funzionalità comegit bisect quasi impossibili da usare se attraversasse una tale incompatibilità del sottomodulo.
Un ulteriore motivo è mostrato sopra. Guarda il ls. Cosa vedi lì?
Bene, la seconda variante del modulo two/non è sotto .git/modules/two/, è sotto .git/modules/someunusedname/! Quindi cose del genere git rm $module; rm -f .git/module/$modulesono totalmente sbagliate! È necessario consultare module/.gito .gitmodulesper trovare la cosa giusta da rimuovere!
Quindi non solo la maggior parte delle altre risposte cade in questa pericolosa trappola, anche le gitestensioni molto popolari avevano questo bug ( ora è stato risolto lì )! Quindi meglio tenere le mani della .git/directory se non esattamente, cosa stai facendo!
E dal punto di vista filosofico, cancellare la storia è sempre sbagliato!
Tranne la meccanica quantistica , come al solito, ma questo è qualcosa di completamente diverso.
Cordiali saluti, probabilmente lo hai indovinato: Hilbix è il mio account GitHub.
git rm modulenameerm -rf .git/modules/modulename