Z korzyścią dla czytelnika, tutaj próbuje się to podsumować i podać krok po kroku, jak to zrobić, jeśli rzeczy nie działają zgodnie z oczekiwaniami. Poniżej znajduje się przetestowany i bezpieczny sposób na pozbycie się submodułu dla git
wersji 2.17
i wyżej :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Jeśli to nie zadziała, patrz poniżej.
- Brak opcji Nic niebezpiecznego. I nawet nie rozważaj robienia więcej!
- Testowane z Debian Buster
2.20.1
i Ubuntu 18.04 2.17.1
.
"$submodule"
jest po prostu podkreślenie, gdzie umieścić nazwę, i że musisz uważać na spacje i tym podobne
- Jeśli w systemie Windows zignoruj pierwszy wiersz i zamień
"$submodule"
na Windows poprawnie podaną ścieżkę do submodułu. (Nie jestem Windows)
Ostrzeżenie!
Nigdy nie dotykaj wnętrza .git
katalogu! Edycja wewnątrz .git
wchodzi w ciemną stronę. Trzymaj się z dala za wszelką cenę!
I tak, można za to winić git
, ponieważ git
w przeszłości brakowało wielu przydatnych rzeczy . Jak właściwy sposób na ponowne usunięcie submodułów.
Myślę, że w dokumentacji jest bardzo niebezpieczna część git submodule
. Zaleca się $GIT_DIR/modules/<name>/
samemu usunąć .
W moim rozumieniu jest to nie tylko błędne, ale także bardzo niebezpieczne i powoduje poważne bóle głowy w przyszłości! Patrz poniżej.
Zauważ, że
git module deinit
jest bezpośrednią odwrotnością do
git module init
ale
git submodule deinit -- module
git rm -- module
jest również odwrotnie
git submodule add -- URL module
git submodule update --init --recursive -- module
ponieważ niektóre polecenia w zasadzie wymagają więcej niż jednej rzeczy:
git submodule deinit -- module
- (1) aktualizacje
.git/config
git rm
- (2) usuwa pliki modułu
- (3) tym samym rekurencyjnie usuwa submoduły submodułu
- (4) aktualizacje
.gitmodules
git submodule add
- ściąga dane do
.git/modules/NAME/
- (1) robi
git submodule init
, więc aktualizuje.git/config
- (2)
git submodule update
tak więc nierekurencyjnie sprawdza moduł
- (4) aktualizacje
.gitmodules
git submodule update --init --recursive -- module
- w razie potrzeby pobiera dalsze dane
- (3) sprawdza rekurencyjnie submoduły submodułu
Nie może to być w pełni symetryczne, ponieważ zachowanie ścisłej symetryczności nie ma większego sensu. Po prostu nie potrzeba więcej niż dwóch poleceń. Również „pobieranie danych” jest niejawne, ponieważ jest ono potrzebne, ale usuwanie buforowanych informacji nie jest wykonywane, ponieważ nie jest to wcale potrzebne i może wyczyścić cenne dane.
To naprawdę jest zagadką dla początkujących, ale w zasadzie jest dobrą rzeczą: git
po prostu robi to, co oczywiste, i robi to dobrze, a nawet nie próbuje robić więcej. git
to narzędzie, które musi wykonać niezawodny zawód, zamiast być kolejnym „Eierlegende Wollmilchsau” („Eierlegende Wollmilchsau” tłumaczy dla mnie „złą wersję szwajcarskiego noża wojskowego”).
Rozumiem więc narzekania ludzi, mówiąc: „Dlaczego nie robi git
dla mnie rzeczy oczywistych”. Jest tak, ponieważ „oczywiste” zależy tutaj z punktu widzenia. Niezawodność w każdej sytuacji jest znacznie ważniejsza. Dlatego to, co dla Ciebie oczywiste, często nie jest właściwe we wszystkich możliwych sytuacjach technicznych. Pamiętaj, że: AFAICS git
podąża ścieżką techniczną, a nie społeczną. (Stąd sprytna nazwa: git)
Jeśli to się nie powiedzie
Powyższe polecenia mogą się nie powieść z powodu:
- Twój
git
jest za stary. Następnie użyj nowszego git
. (Zobacz poniżej, jak to zrobić).
- Masz nieprzydzielone dane i możesz stracić dane. Więc lepiej najpierw je poproś.
- Twój podmoduł nie jest w pewnym
git clean
sensie czysty . Następnie najpierw wyczyść swój moduł podrzędny za pomocą tego polecenia. (Patrz poniżej.)
- Zrobiłeś coś w przeszłości, co nie jest wspierane przez
git
. Jesteś wtedy po ciemnej stronie, a sprawy stają się brzydkie i skomplikowane. (Być może użycie innego komputera to naprawia.)
- Być może istnieje więcej sposobów na porażkę, o których nie wiem (jestem tylko pewnym
git
użytkownikiem zaawansowanym).
Możliwe są następujące poprawki.
Użyj nowszej git
Jeśli urządzenie jest zbyt stary, tam nie jest submodule deinit
w twojej git
. Jeśli nie chcesz (lub możesz) zaktualizować swojego git
, skorzystaj z innego komputera z nowszym git
! git
jest przeznaczony do pełnej dystrybucji, więc możesz użyć innego, git
aby wykonać zadanie:
workhorse:~/path/to/worktree$ git status --porcelain
nie wolno niczego wydawać! Jeśli tak, najpierw posprzątaj rzeczy!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Teraz wykonaj czynności związane z submodułem
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
. Jeśli to nie zadziała, użyjgit reset --soft FETCH_HEAD
- Teraz
git status
oczyść rzeczy, aż znów będzie czysty. Jesteś w stanie to zrobić, ponieważ już wcześniej wyczyściłeś go, dzięki pierwszemu krokowi.
Może othermachine
to być jakaś maszyna wirtualna lub Ubuntu WSL pod Windows, cokolwiek. Nawet a chroot
(ale zakładam, że nie jesteś rootem, ponieważ jeśli tak, root
to łatwiej jest zaktualizować do nowszej wersji git
).
Pamiętaj, że jeśli nie możesz ssh
wejść, istnieje wiele sposobów transportu git
repozytoriów. Możesz skopiować swój zestaw roboczy na pamięć USB (w tym .git
katalog) i sklonować z pamięci USB . Sklonuj kopię, aby ponownie uzyskać porządek. Może to być PITA, na wypadek gdyby Twoje podmoduły nie były dostępne bezpośrednio z innej maszyny. Ale jest na to również rozwiązanie:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Możesz użyć tego mnożenia, i to jest zapisane w $HOME/.gitconfig
. Coś jak
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
przepisuje adresy URL takie jak
https://github.com/XXX/YYY.git
w
/mnt/usb/repo/XXX/YYY.git
Łatwo jest przyzwyczaić się do git
takich zaawansowanych funkcji.
Najpierw posprzątaj rzeczy
Ręczne czyszczenie jest dobre, ponieważ w ten sposób możesz wykryć niektóre rzeczy, o których zapomniałeś.
- Jeśli git narzeka na niezapisane rzeczy, zatwierdzaj je i pchaj w bezpieczne miejsce.
- Jeśli git narzeka na resztki
git status
i git clean -ixfd
jest twoim przyjacielem
- Staraj się powstrzymywać od opcji
rm
i deinit
tak długo, jak możesz. Opcje (jak -f
) git
są dobre, jeśli jesteś profesjonalistą. Ale kiedy tu przyjechałeś, prawdopodobnie nie jesteś tak doświadczony w submodule
okolicy. Więc lepiej bądź bezpieczny niż przykro.
Przykład:
$ 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'
Widzisz, nie ma takiej -f
potrzeby submodule deinit
. W pewnym git clean
sensie rzeczy są czyste . Pamiętaj również, że git clean -x
nie jest to konieczne. Oznacza to git submodule deinit
bezwarunkowe usuwanie nieśledzonych plików, które są ignorowane. Jest to zwykle to, czego chcesz, ale nie zapominaj o tym. Czasami ignorowane pliki mogą być cenne, jak dane w pamięci podręcznej, których ponowne obliczenie zajmuje kilka godzin lub dni.
Dlaczego nigdy nie usuwać $GIT_DIR/modules/<name>/
?
Prawdopodobnie ludzie chcą usunąć buforowane repozytorium, ponieważ boją się później napotkać problem. To prawda, ale napotkanie tego „problemu” jest właściwym sposobem na jego rozwiązanie! Ponieważ naprawa jest łatwa i wykonana poprawnie, będziesz mógł żyć długo i szczęśliwie. Pozwala to uniknąć kłopotliwych problemów niż podczas samodzielnego usuwania danych.
Przykład:
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
Ostatni wiersz wyświetla następujący błąd:
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.
Dlaczego ten błąd? Ponieważ .git/modules/two/
wcześniej był wypełniany z https://github.com/hilbix/empty.git, a teraz zostanie ponownie wypełniony z czegoś innego, mianowicie https://github.com/hilbix/src.git . Nie zobaczysz tego, jeśli ponownie wypełnisz go z https://github.com/hilbix/empty.git
Co zrobić teraz? Zrób dokładnie to, co powiedziano! Posługiwać się--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules
wtedy wygląda jak
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/
daje
someunusedname/
two/
W ten sposób w przyszłości możesz przełączać gałęzie / zatwierdzać do przodu i do tyłu i nigdy więcej nie będziesz mieć kłopotów z powodu two/
posiadania dwóch różnych (i prawdopodobnie niekompatybilnych) repozytoriów. A najlepsze jest to, że przechowujesz je w pamięci podręcznej również lokalnie.
- Dotyczy to nie tylko ciebie. Dotyczy to również wszystkich innych korzystających z Twojego repozytorium.
- I nie tracisz historii. Jeśli zapomniałeś wypchnąć najnowszą wersję starego podmodułu, możesz wprowadzić lokalną kopię i zrobić to później. Zauważ, że często zdarza się, że ktoś zapomina pchnąć jakieś podmoduły (ponieważ jest to PITA dla nowoprzybyłych, dopóki się nie przyzwyczai
git
).
Jeśli jednak usuniesz buforowany katalog, obie różne kasy natkną się na siebie, ponieważ nie użyjesz --name
opcji, prawda? Dlatego za każdym razem, gdy robisz kasę, być może będziesz musiał ciągle usuwać .git/modules/<module>/
katalog. Jest to bardzo uciążliwe i utrudnia korzystanie z czegoś takiego git bisect
.
Jest więc bardzo techniczny powód, aby zachować ten katalog modułów jako symbol zastępczy. Ludzie, którzy zalecają usunięcie czegoś poniżej, .git/modules/
albo nie wiedzą lepiej, albo zapominają powiedzieć, że powoduje to, że potężne funkcje są git bisect
prawie niemożliwe do użycia, jeśli powoduje to niezgodność submodułu.
Kolejny powód pokazano powyżej. Spójrz na ls
. Co tam widzisz
Cóż, drugi wariant modułu two/
nie jest pod .git/modules/two/
, jest pod .git/modules/someunusedname/
! Takie rzeczy git rm $module; rm -f .git/module/$module
są całkowicie błędne! Musisz albo skonsultować się, module/.git
albo .gitmodules
znaleźć właściwą rzecz do usunięcia!
Więc nie tylko większość innych odpowiedzi wpada w tę niebezpieczną pułapkę, nawet bardzo popularne git
rozszerzenia miały ten błąd ( teraz jest tam naprawiony )! Więc lepiej trzymaj ręce w .git/
katalogu, jeśli nie dokładnie to, co robisz!
A z filozoficznego punktu widzenia wymazywanie historii zawsze jest złe!
Z wyjątkiem mechaniki kwantowej , jak zwykle, ale jest to coś zupełnie innego.
Dla pewnie zgadłeś: hilbix to moje konto GitHub.
git rm modulename
irm -rf .git/modules/modulename