Олег Марков
Удаление подмодуля - git submodule deinit
Введение
Подмодули в Git кажутся удобным инструментом, пока не приходится их удалять. На этапе добавления все выглядит просто, а вот когда нужно аккуратно убрать подмодуль из репозитория, истории и рабочего каталога, начинают появляться вопросы: какие команды запускать, что сначала, как не сломать основной проект?
Здесь мы разберем, как правильно удалять подмодуль, зачем нужна команда git submodule deinit, чем она отличается от простого удаления папки и какие шаги нужно выполнить, чтобы не оставлять «мусор» в конфигурации и индексе Git.
Смотрите, я покажу вам последовательный и безопасный сценарий, который можно применять в реальных проектах, а также объясню, что происходит «под капотом».
Что такое git submodule и почему его удаление не тривиально
Кратко о том, как устроен подмодуль
Когда вы добавляете подмодуль в Git, происходит несколько вещей:
- В корне или нужной директории создается каталог с «вложенным» Git-репозиторием (подмодуль).
- В основной репозиторий добавляется «ссылка» на конкретный коммит подмодуля (это не обычная папка, а особый тип объекта —
gitlink). - В файл
.gitmodulesзаписывается конфигурация подмодуля:- его логическое имя;
- путь в рабочем дереве;
- URL удаленного репозитория.
- В
.git/configдобавляются локальные настройки подмодуля (например, URL, ветка по умолчанию и др.).
Из-за этого подмодуль «присутствует» в нескольких местах сразу:
- в файловой системе (каталог подмодуля);
- в индексe (как gitlink-объект);
- в
.gitmodules(конфигурация проекта); - в
.git/config(локальная конфигурация).
Поэтому, если просто удалить папку подмодуля из файловой системы, Git продолжит «думать», что подмодуль есть, и будет показывать его как измененный/сломанный. Именно здесь в игру вступает git submodule deinit.
Задача команды git submodule deinit
Что делает git submodule deinit
Команда git submodule deinit удаляет локальную конфигурацию подмодуля из .git/config и разрывает связь рабочего каталога с этим подмодулем.
Давайте разберем на словах:
- Git «забывает», что данный путь управляется подмодулем.
- Рабочий каталог подмодуля очищается (если вы укажете флаг
--force, при необходимости Git удалит несохраненные изменения). - Локальные настройки подмодуля удаляются из
.git/config, но записи в.gitmodulesи индекс основной репозитории остаются. То есть связь в истории еще существует.
Важно понимать: git submodule deinit — это не финальное «удаление подмодуля из проекта», а подготовительный шаг. После него вам нужно еще:
- удалить запись из
.gitmodules; - удалить gitlink из индекса (обычно с помощью
git rm); - закоммитить изменения.
Типичная ошибка — просто удалить папку
Многие разработчики делают так:
- удаляют каталог подмодуля через файловый менеджер или
rm -rf; - коммитят изменения.
Результат:
- Git видит, что путь подмодуля исчез из рабочего дерева, но конфигурация в
.gitmodulesи индексe сохранилась; - команда
git statusпоказывает странные изменения; - иногда при клонировании/обновлении репозитория другие разработчики видят ошибки, связанные с подмодулем.
git submodule deinit нужен как раз для корректного «отключения» подмодуля перед его окончательным удалением из проекта.
Базовый сценарий удаления подмодуля с помощью git submodule deinit
Смотрите, я покажу вам базовый, самый безопасный сценарий пошагово. Допустим, путь к подмодулю: libs/my-submodule.
Шаг 1. Проверяем статус подмодулей
Сначала посмотрите, какие подмодули есть и в каком они состоянии:
git submodule status
# Вывод может выглядеть так
# e1a2b3c4d5e6f7g8h9i0 libs/my-submodule (heads/main)
# 1234567890abcdef1234 other/module (heads/master)
Комментарий:
- Здесь вы видите список подмодулей и коммиты, на которые ссылается основной репозиторий.
- Убедитесь, что вы действительно хотите удалить нужный путь, а не перепутали его с другим.
Шаг 2. Деинициализация подмодуля
Теперь выполняем деинициализацию:
git submodule deinit libs/my-submodule
Что здесь происходит:
- Git удаляет секцию настроек подмодуля
submodule.libs/my-submoduleиз.git/config. - Рабочий каталог подмодуля может быть очищен. Если в нем есть несохраненные изменения, Git может отказать без флага
--force.
Если в подмодуле есть незакоммиченные изменения, вы можете увидеть ошибку вида:
Submodule work tree 'libs/my-submodule' contains local modifications
Use '-f' to discard local changes
В этом случае варианты:
- Закоммитить изменения внутри подмодуля и запушить в его репозиторий.
- Сохранить изменения куда-то отдельно (например, через
git diff > patch). - Принять решение удалить их безвозвратно, добавив
-f.
Для жесткого отключения:
git submodule deinit -f libs/my-submodule
# -f (или --force) говорит Git - можно удалить локальные изменения в рабочем каталоге подмодуля
Шаг 3. Удаление записи о подмодуле из индекса и файловой системы
После deinit подмодуль еще присутствует в индексе основной репозитории как gitlink. Чтобы убрать его, используем git rm:
git rm libs/my-submodule
# Эта команда:
# 1. Удалит gitlink из индекса
# 2. Удалит сам каталог 'libs/my-submodule' из рабочего дерева (если он еще существует)
Обратите внимание:
git rmработает с индексом. Он не только удаляет каталог, но и обновляет состояние репозитория.- Если вы уже удаляли папку руками,
git rmвсе равно нужен — чтобы удалить gitlink из индекса.
Шаг 4. Очистка файла .gitmodules
Теперь давайте посмотрим содержимое .gitmodules:
cat .gitmodules
# Пример содержимого
# [submodule "libs/my-submodule"]
# path = libs/my-submodule
# url = git@github.com:org/my-submodule.git
# [submodule "other/module"]
# path = other/module
# url = git@github.com:org/other-module.git
Здесь вы увидите секцию, соответствующую удаленному подмодулю. Вам нужно удалить ее вручную (в любом текстовом редакторе) или с помощью команды:
Если хотите отредактировать через sed (пример для Linux/macOS):
# Удаляем блок submodule "libs/my-submodule" из .gitmodules
# Будьте внимательны - сначала лучше сделать резервную копию файла
cp .gitmodules .gitmodules.bak
sed -i '' '/submodule "libs\/my-submodule"/,/^$/d' .gitmodules
Комментарий:
- Здесь мы удаляем блок от строки с
submodule "libs/my-submodule"до первой пустой строки. - Если вы не уверены, проще сделать это руками в редакторе.
После изменений в .gitmodules не забудьте добавить файл в индекс:
git add .gitmodules
Шаг 5. Проверка статуса и коммит изменений
Теперь посмотрим, что изменилось:
git status
# Должны быть:
# - удаленный путь libs/my-submodule
# - измененный .gitmodules
Далее фиксируем изменения:
git commit -m "Remove submodule libs/my-submodule"
После этого:
- Подмодуль больше не присутствует в проекте.
- Настройки в
.gitmodulesи индексе актуальны. - Другие разработчики при
git pullилиgit cloneбольше не увидят этот подмодуль.
Как работает git submodule deinit внутри
Где хранятся настройки подмодулей
Чтобы лучше понимать, что делает deinit, давайте разберем конфигурационные файлы.
.gitmodules— версия-контролируемый файл в корне репозитория:Пример:
[submodule "libs/my-submodule"] path = libs/my-submodule url = git@github.com:org/my-submodule.gitКомментарий:
- Этот файл отслеживается Git и синхронизируется между всеми разработчиками.
- Он описывает, какие подмодули существуют в проекте.
.git/config— локальная конфигурация:Пример фрагмента:
[submodule "libs/my-submodule"] url = git@github.com:org/my-submodule.git active = trueКомментарий:
- Этот файл не коммитится.
- Здесь хранятся локальные настройки, в том числе
active = true, что означает, что подмодуль инициализирован.
Когда вы выполняете:
git submodule deinit libs/my-submodule
Git делает примерно следующее:
- Находит секцию
submodule "libs/my-submodule"в.git/config. - Удаляет или изменяет параметр
active, фактически отключая подмодуль. - Может очистить рабочий каталог подмодуля (перевести его в «отключенное» состояние).
Файл .gitmodules при этом не трогается — именно поэтому его нужно править отдельно.
Флаги и дополнительные опции git submodule deinit
Давайте посмотрим, какие флаги чаще всего полезны.
Флаг -f или --force
Используется, когда внутри подмодуля есть несохраненные изменения, а вы хотите их отбросить:
git submodule deinit -f libs/my-submodule
Эта команда:
- удалит локальные изменения в рабочем каталоге подмодуля;
- деинициализирует подмодуль.
Применяйте ее только когда уверены, что все нужные изменения в подмодуле уже сохранены или не нужны.
Деинициализация всех подмодулей
Если вам нужно отключить все подмодули разом:
git submodule deinit --all
# или с принудительным сбросом локальных изменений
git submodule deinit --all --force
Такой сценарий иногда используют:
- перед архивированием проекта;
- когда хотят временно «облегчить» рабочее дерево.
Альтернативные сценарии: временное отключение подмодуля vs полное удаление
Иногда вы хотите не удалить подмодуль навсегда, а:
- временно отключить его;
- или удалить только у себя локально.
Здесь полезно различать два сценария.
Временное отключение подмодуля
Если цель — просто «забыть» подмодуль локально (например, он вам не нужен на этой машине), можно:
git submodule deinit libs/my-submodule
И на этом остановиться, не делая git rm и не редактируя .gitmodules.
В результате:
- в истории репозитория подмодуль остается;
- другие разработчики его по-прежнему используют;
- у вас локально рабочий каталог подмодуля может быть очищен, а настройки — удалены.
Позже, если вы захотите вернуть его:
git submodule update --init libs/my-submodule
# Эта команда:
# 1. Заново создаст рабочий каталог подмодуля
# 2. Инициализирует его на нужный коммит
Полное удаление подмодуля из проекта
Это тот сценарий, который мы разбирали выше.
Кратко шаги:
git submodule deinit [-f] path/to/submodulegit rm path/to/submodule- Удаление секции из
.gitmodules git add .gitmodulesgit commit
Такой подход нужен, когда:
- подмодуль больше не используется;
- вы заменили его на код, скопированный прямо в проект;
- решили перейти, например, на Git subtree или иной способ включения внешнего кода.
Типовые ошибки и как их избежать
Ошибка 1. Забыли обновить .gitmodules
Сценарий:
- вы выполнили
git submodule deinitиgit rm; - но не удалили соответствующий блок из
.gitmodules.
Последствия:
- файл
.gitmodulesвсе еще говорит, что в проекте есть этот подмодуль; - другие разработчики при
git submodule update --initмогут увидеть ошибки.
Решение:
- всегда проверяйте содержимое
.gitmodulesпосле операций с подмодулями; - удаляйте лишние секции и коммитьте изменения.
Ошибка 2. Удалили папку руками
Сценарий:
- вы удалили каталог подмодуля через файловую систему:
rm -rf libs/my-submodule;
- не запускали
git rmиgit submodule deinit.
Последствия:
git statusпоказывает путь подмодуля как «удаленный» или измененный;- внутри индекса все еще хранится gitlink-ссылка;
.gitmodulesссылается на несуществующий каталог.
Решение:
- Восстановите текущее состояние из истории (если нужно):
bash git checkout HEAD -- libs/my-submodule - Затем выполните правильную последовательность:
bash git submodule deinit -f libs/my-submodule git rm libs/my-submodule sed -i '' '/submodule "libs/my-submodule"/,/^$/d' .gitmodules # или вручную git add .gitmodules git commit -m "Remove submodule libs/my-submodule"
Ошибка 3. Потеря нужных изменений внутри подмодуля
Бывает ситуация, когда вы изменяли код в подмодуле, но не закоммитили эти изменения в репозиторий подмодуля. Затем выполняете:
git submodule deinit -f libs/my-submodule
И ваши изменения исчезают.
Чтобы этого не произошло:
- Перед
deinitубедитесь, что в подмодуле нет незакоммиченных изменений:bash cd libs/my-submodule git status - Если изменения есть:
- либо закоммитьте их в подмодуль;
- либо сохраните с помощью патча:
bash git diff > ~/my-submodule-changes.patch # После этого можно применить патч в другом месте
- Только после этого используйте
-f.
Пример полного удаления подмодуля шаг за шагом
Давайте разберемся на конкретном сценарии.
Предположим, у вас есть репозиторий:
- основной проект;
- подмодуль
vendor/logger(внешний репозиторий логгера); - вы решили заменить его на собственную реализацию и хотите полностью удалить подмодуль.
Шаги:
Проверяем подмодули:
git submodule status # abcdef1234567890 vendor/logger (heads/main)Убеждаемся, что в подмодуле нет незакоммиченных изменений:
cd vendor/logger git status # working tree clean cd ../../Деинициализируем подмодуль:
git submodule deinit vendor/loggerУдаляем подмодуль из индекса и файловой системы:
git rm vendor/logger # Комментарий: # git rm обновит индекс и удалит каталог vendor/loggerРедактируем
.gitmodules(руками или командой) и удаляем блок:[submodule "vendor/logger"] path = vendor/logger url = git@github.com:some-org/logger.gitДобавляем обновленный
.gitmodulesв индекс:git add .gitmodulesПроверяем статус:
git status # Должны быть изменения: # - deleted: vendor/logger # - modified: .gitmodulesФиксируем изменения:
git commit -m "Remove logger submodule vendor/logger"
Теперь подмодуль удален полностью и корректно.
Если вы после этого добавите новый код логгера прямо в дерево проекта (как обычные файлы), он не будет связан с прежним подмодулем.
Работа с историей после удаления подмодуля
Что происходит с прошлыми коммитами
Важно понимать, что удаление подмодуля:
- не переписывает историю;
- не изменяет старые коммиты.
Это означает:
- если вы откатитесь на старый коммит, где подмодуль еще существовал, он снова появится как подмодуль;
git checkout <старый-коммит>покажет вам состояние проекта с подмодулем.
То есть git submodule deinit и последующее удаление — это изменение текущего состояния и новых коммитов, но не прошлых.
Как клон репозитория ведет себя после удаления подмодуля
Если новый разработчик клонирует ваш репозиторий после того, как вы удалили подмодуль, он увидит:
- обычный проект без подмодуля;
.gitmodulesбез записей о нем.
Если же он захочет перейти на старую версию:
git checkout <старый-коммит-с-подмодулем>
git submodule update --init --recursive
Git:
- увидит, что в этом коммите есть подмодуль;
- инициализирует его согласно данным старого
.gitmodules.
Это нормальное и ожидаемое поведение.
Заключение
Удаление подмодуля в Git — это не одна команда, а несколько последовательных шагов. Команда git submodule deinit отвечает только за одну часть задачи: она деинициализирует подмодуль, удаляет его локальные настройки и «отвязывает» рабочий каталог.
Чтобы удалить подмодуль корректно:
- Деинициализируйте его с помощью
git submodule deinit, при необходимости с флагом-f. - Удалите путь подмодуля из индекса и файловой системы с помощью
git rm. - Очистите файл
.gitmodules, удалив соответствующую секцию. - Зафиксируйте изменения в коммите.
При таком подходе:
- проект не будет содержать «висящих» ссылок на несуществующие подмодули;
- другие разработчики не столкнутся с ошибками при работе с репозиторием;
- история останется целостной, а старые коммиты — воспроизводимыми.
Обратите внимание на разницу между временной деинициализацией подмодуля и его полным удалением из проекта. git submodule deinit сама по себе не «стирает» подмодуль из истории и не убирает его из .gitmodules, а лишь делает первый шаг.
Частозадаваемые технические вопросы по теме и ответы
Вопрос 1. Как удалить подмодуль только локально не затрагивая репозиторий для других разработчиков
Если вы хотите убрать подмодуль только у себя, но не менять репозиторий:
- Выполните:
bash git submodule deinit path/to/submodule - Не трогайте
.gitmodulesи не используйтеgit rm. - Файл
.gitmodulesи индекс не меняются, а у вас локально подмодуль деинициализирован.
Позже его можно вернуть:bash git submodule update --init path/to/submodule
Вопрос 2. Как восстановить подмодуль после ошибочного удаления
Если вы уже удалили подмодуль (с коммитом), но хотите вернуть его:
- Найдите старый коммит, где подмодуль еще был, с помощью
git log. - Посмотрите содержимое
.gitmodulesв том коммите:bash git show <commit>:.gitmodules - Восстановите нужный блок в текущем
.gitmodules. - Добавьте подмодуль заново:
bash git submodule add <url> <path> - Закоммитьте изменения.
Вопрос 3. Что делать если .gitmodules поврежден или удален но подмодуль еще есть в истории
Если .gitmodules случайно удален или испорчен:
- Восстановите его из прошлого коммита:
bash git checkout HEAD~1 -- .gitmodulesили из нужной версии, где он корректен. - При необходимости отредактируйте.
- Добавьте в индекс и закоммитьте:
bash git add .gitmodules git commit -m "Restore .gitmodules"
Вопрос 4. Как проверить какие подмодули сейчас активны после deinit
Чтобы увидеть, какие подмодули инициализированы:
- Посмотрите
.git/config:bash cat .git/config # ищите секции [submodule "..."] с параметром active - Используйте:
bash git submodule statusПодмодули, которые были деинициализированы, могут отображаться с префиксом-или как неинициализированные.
Вопрос 5. Можно ли полностью удалить историю подмодуля из основного репозитория
История подмодуля хранится в его собственном репозитории, а в основном хранятся только ссылки на коммиты. Полностью «вычистить» следы подмодуля из истории основного репозитория можно только переписав историю (например, с помощью git filter-repo):
- Используйте
git filter-repoилиgit filter-branch, чтобы удалить путь подмодуля из всех коммитов. - Это изменит историю, так что всем участникам проекта придется заново синхронизировать репозиторий.
- Такой подход стоит применять только в исключительных случаях.
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

Основы Git
Антон Ларичев
TypeScript с нуля
Антон Ларичев