На користь читача, це тут намагається підсумувати його та дати покрокове керівництво щодо того, як це зробити, якщо все не працює так, як очікувалося. Далі йде перевірений і безпечний спосіб для gitверсії 2.17та вище для позбавлення від підмодуля :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Якщо це не допоможе вам, дивіться нижче.
- Немає варіантів. Нічого небезпечного. І навіть не думайте робити більше!
- Тестовано з Debian Buster
2.20.1та Ubuntu 18.04 2.17.1.
"$submodule" це лише підкреслити, де слід вказати ім’я, і що вам слід бути обережними з пробілами тощо
- Якщо в Windows ігноруйте перший рядок і замініть
"$submodule"Windows способом правильно вказаного шляху до підмодуля. (Я не Windows)
Увага!
Ніколи не торкайтеся нутрощів .gitкаталогу самостійно! Редагування всередині.git переходить у темну сторону. Тримайтеся подалі за будь-яку ціну!
І так, ви можете звинуватити gitв цьому, оскільки багато корисних речей не вистачалоgit минулому. Як правильний спосіб знову видалити підмодулі.
Я думаю, що в документації Росії є дуже небезпечна частина git submodule. Рекомендує зняти $GIT_DIR/modules/<name>/себе.
На моє розуміння, це не просто невірно, це надзвичайно небезпечно і провокує великі головні болі в майбутньому! Дивись нижче.
Зауважте, що
git module deinit
є прямою оберненою до
git module init
але
git submodule deinit -- module
git rm -- module
також є досить зворотним
git submodule add -- URL module
git submodule update --init --recursive -- module
тому що деяким командам в основному потрібно зробити більше, ніж просто одну річ:
git submodule deinit -- module
- (1) оновлення
.git/config
git rm
- (2) видаляє файли модуля
- (3) тим самим рекурсивно видаляє підмодулі підмодуля
- (4) оновлення
.gitmodules
git submodule add
- тягне дані до
.git/modules/NAME/
- (1) робить
git submodule init, тому оновлення.git/config
- (2) робить
git submodule update, таким чином, нерекурсивно перевіряє модуль
- (4) оновлення
.gitmodules
git submodule update --init --recursive -- module
- за потреби подає додаткові дані
- (3) рекурсивно перевіряє підмодулі підмодуля
Це не може бути повністю симетричним, оскільки зберігати його строго симетрично не має особливого сенсу. Просто не потрібно більше двох команд. Також "втягування даних" є неявним, оскільки вам це потрібно, але видалення кешованої інформації не робиться, оскільки це зовсім не потрібно і може стерти дорогоцінні дані.
Це справді дивовижне для новачків, але в основному це добре: gitпросто робить очевидно і робить це правильно, і навіть не намагається робити більше. gitце інструмент, який повинен зробити надійну роботу, а не бути лише черговим "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" перекладається для мене "якоюсь злою версією ножа швейцарської армії").
Тож я розумію скарги людей, кажучи: "Чому я не робиш gitочевидного для мене". Це тому, що "очевидне" тут залежить від точки зору. Надійність у кожній ситуації набагато важливіша. Отже, те, що для вас очевидно, часто не є правильним у всіх можливих технічних ситуаціях. Пам'ятайте про це: AFAICS gitслідує технічному шляху, а не соціальному. (Звідси розумна назва: git)
Якщо це не вдасться
Команди, наведені вище, можуть не працювати через:
- Ваш
gitзанадто старий. Потім використовуйте новіший git. (Дивіться нижче, як це зробити.)
- Ви не передали дані і можете втратити дані. Тоді краще спочатку скопіюйте їх.
- Ваш підмодуль у певному
git cleanсенсі не чистий . Потім спочатку очистіть підмодуль за допомогою цієї команди. (Дивись нижче.)
- Ви раніше робили щось, що не підтримується
git . Тоді ви на темній стороні, і справи стають потворними і складними. (Можливо, використання іншої машини виправляє це.)
- Можливо, є більше способів невдачі, про які я не знаю (я просто якийсь
gitвладний користувач.)
Наступні можливі виправлення.
Використовуйте новіший git
Якщо Ваш апарат занадто старий , немає submodule deinitв вашому git. Якщо ви не хочете (або можете) оновити свою git, тоді просто використовуйте іншу машину з новішою git! gitпризначений для повного розповсюдження, тому ви можете використовувати іншу, gitщоб виконати роботу:
workhorse:~/path/to/worktree$ git status --porcelain не повинен нічого виводити! Якщо це так, спочатку почистіть речі!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Тепер робимо підмодуль
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. Якщо це не працює, використовуйтеgit reset --soft FETCH_HEAD
- Тепер прибирайте речі, поки
git statusзнову не буде чисто. Ви можете це зробити, тому що ви очистили це раніше, завдяки першому кроку.
Це othermachineможе бути якийсь VM або якийсь Ubuntu WSL під Windows. Навіть chroot(але я припускаю, що ви не кореневий, тому що, якщо ви є, rootйого слід легше оновити на новіші git).
Зауважте, що якщо ви не можете sshввійти, існує набір шляхів транспортування gitсховищ. Ви можете скопіювати своє робоче дерево на якийсь USB-накопичувач (включаючи .gitкаталог) та клонувати його з флешки. Клонуйте копію, просто щоб знову зробити речі в чистому вигляді. Це може бути PITA, якщо ваші підмодулі не доступні безпосередньо з інших машин. Але і для цього є рішення:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Ви можете використовувати це множення, і це зберігається в $HOME/.gitconfig. Щось на зразок
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
переписує такі URL-адреси, як
https://github.com/XXX/YYY.git
в
/mnt/usb/repo/XXX/YYY.git
Це легко, якщо ви почнете звикати до таких потужних gitфункцій.
Спочатку почистіть речі
Чистка вручну - це добре, тому що ви, можливо, виявляєте деякі речі, про які ви забули.
- Якщо git поскаржиться на незбережені речі, зробіть їх і кудись надійніше.
- Якщо git скаржиться на деякі залишки,
git statusіgit clean -ixfd це ваш друг
- Постарайтеся утриматися від варіантів
rmі до deinitтих пір, поки зможете. Параметри (як -f) для gitхороших, якщо ви професіонал. Але, як ви приїхали сюди, ви, мабуть, не так досвідчені в цьому submoduleрайоні. Тож краще бути в безпеці, ніж шкодувати.
Приклад:
$ 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'
Розумієте, немає -fнеобхідності на submodule deinit. Якщо речі чисті, в певному git cleanсенсі. Також зауважте, що git clean -xце не потрібно. Це означає, що git submodule deinitбезумовно видаляються незатребувані файли, які ігноруються. Зазвичай це те, що ви хочете, але не забувайте про це. Іноді ігноровані файли можуть бути дорогоцінними, як кешовані дані, на які потрібно заново обчислювати години.
Чому ніколи не видаляють $GIT_DIR/modules/<name>/?
Можливо, люди хочуть видалити кешований сховище, оскільки вони бояться зіткнутися з проблемою пізніше. Це правда, але наткнутися на цю "проблему" - це правильний спосіб її вирішити! Оскільки виправити це легко, і правильно зробити, ви зможете жити щасливо до цього часу. Це дозволяє уникнути більш громіздких проблем, ніж при видаленні даних самостійно.
Приклад:
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
Останній рядок видає наступну помилку:
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.
Чому ця помилка? Оскільки .git/modules/two/раніше було заповнено з https://github.com/hilbix/empty.git, а тепер буде повторно заселене чимось іншим, а саме https://github.com/hilbix/src.git . Ви не побачите цього, якщо повторно заселите його з https://github.com/hilbix/empty.git
Що ж тепер робити? Ну просто роби точно так, як сказано! Використовуйте--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules то схожий
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/ дає
someunusedname/
two/
Таким чином, у майбутньому ви можете перемикати гілки / здійснювати вперед та назад і більше ніколи не потраплятимете в будь-які проблеми через two/наявність двох різних (і, можливо, несумісних) сховищ вище. А найкраще: Ви обидва зберігаєте кешований локально.
- Це стосується не тільки вас. Це також справедливо для всіх інших, що використовують ваше сховище.
- І ви не втрачаєте історію. Якщо ви забули натиснути саму останню версію старого підмодуля, ви можете ввести локальну копію і зробити це пізніше. Зауважте, що досить часто хтось забуває натиснути на якісь підмодулі (адже це ПДФА для новачків, поки вони не звикли
git).
Однак якщо ви видалили кешований каталог, обидві різні каси натикатимуться один на одного, тому що ви не будете використовувати --nameваріанти, правда? Тому щоразу, коли ви здійснюєте оформлення замовлення, вам, можливо, доведеться видаляти .git/modules/<module>/каталог знову і знову. Це надзвичайно громіздко і ускладнює використання чогось подібного git bisect.
Тому є дуже технічна причина зберегти цей каталог модулів як заповнювач. Люди, які рекомендують видалити щось нижче, .git/modules/або не знають краще, або забувають сказати вам, що це робить такі потужні функції, якgit bisect майже неможливо використовувати, якщо це перетинає таку несумісність підмодуля.
Наступна причина показана вище. Подивись наls . Що ти там бачиш?
Ну, 2-й варіант модуля two/не під .git/modules/two/, він під .git/modules/someunusedname/! Тож такі речі git rm $module; rm -f .git/module/$moduleабсолютно неправильні! Ви повинні або проконсультуватися, module/.gitабо.gitmodules знайти потрібну річ, яку потрібно видалити!
Тож не лише більшість інших відповідей потрапляють у цю небезпечну пастку, навіть дуже популярні gitрозширення мали цю помилку ( вона зараз виправлена )! Тож краще тримати свої .git/довідники, якщо ви точно не робите, що робите!
І з філософського погляду витирання історії завжди неправильне!
За винятком квантової механіки , як завжди, але це щось зовсім інше.
FYI ви, напевно, здогадалися: hilbix - це мій обліковий запис GitHub.
git rm modulenameіrm -rf .git/modules/modulename