Удаление подмодуля - git submodule deinit

17 декабря 2025
Автор

Олег Марков

Введение

Подмодули в Git кажутся удобным инструментом, пока не приходится их удалять. На этапе добавления все выглядит просто, а вот когда нужно аккуратно убрать подмодуль из репозитория, истории и рабочего каталога, начинают появляться вопросы: какие команды запускать, что сначала, как не сломать основной проект?

Здесь мы разберем, как правильно удалять подмодуль, зачем нужна команда git submodule deinit, чем она отличается от простого удаления папки и какие шаги нужно выполнить, чтобы не оставлять «мусор» в конфигурации и индексе Git.

Смотрите, я покажу вам последовательный и безопасный сценарий, который можно применять в реальных проектах, а также объясню, что происходит «под капотом».


Что такое git submodule и почему его удаление не тривиально

Кратко о том, как устроен подмодуль

Когда вы добавляете подмодуль в Git, происходит несколько вещей:

  1. В корне или нужной директории создается каталог с «вложенным» Git-репозиторием (подмодуль).
  2. В основной репозиторий добавляется «ссылка» на конкретный коммит подмодуля (это не обычная папка, а особый тип объекта — gitlink).
  3. В файл .gitmodules записывается конфигурация подмодуля:
    • его логическое имя;
    • путь в рабочем дереве;
    • URL удаленного репозитория.
  4. В .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

В этом случае варианты:

  1. Закоммитить изменения внутри подмодуля и запушить в его репозиторий.
  2. Сохранить изменения куда-то отдельно (например, через git diff > patch).
  3. Принять решение удалить их безвозвратно, добавив -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, давайте разберем конфигурационные файлы.

  1. .gitmodules — версия-контролируемый файл в корне репозитория:

    Пример:

    [submodule "libs/my-submodule"]
      path = libs/my-submodule
      url = git@github.com:org/my-submodule.git
    

    Комментарий:

    • Этот файл отслеживается Git и синхронизируется между всеми разработчиками.
    • Он описывает, какие подмодули существуют в проекте.
  2. .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. Инициализирует его на нужный коммит

Полное удаление подмодуля из проекта

Это тот сценарий, который мы разбирали выше.

Кратко шаги:

  1. git submodule deinit [-f] path/to/submodule
  2. git rm path/to/submodule
  3. Удаление секции из .gitmodules
  4. git add .gitmodules
  5. git 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 ссылается на несуществующий каталог.

Решение:

  1. Восстановите текущее состояние из истории (если нужно): bash git checkout HEAD -- libs/my-submodule
  2. Затем выполните правильную последовательность: 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

И ваши изменения исчезают.

Чтобы этого не произошло:

  1. Перед deinit убедитесь, что в подмодуле нет незакоммиченных изменений: bash cd libs/my-submodule git status
  2. Если изменения есть:
    • либо закоммитьте их в подмодуль;
    • либо сохраните с помощью патча: bash git diff > ~/my-submodule-changes.patch # После этого можно применить патч в другом месте
  3. Только после этого используйте -f.

Пример полного удаления подмодуля шаг за шагом

Давайте разберемся на конкретном сценарии.

Предположим, у вас есть репозиторий:

  • основной проект;
  • подмодуль vendor/logger (внешний репозиторий логгера);
  • вы решили заменить его на собственную реализацию и хотите полностью удалить подмодуль.

Шаги:

  1. Проверяем подмодули:

    git submodule status
    #  abcdef1234567890 vendor/logger (heads/main)
    
  2. Убеждаемся, что в подмодуле нет незакоммиченных изменений:

    cd vendor/logger
    git status
    # working tree clean
    cd ../../
    
  3. Деинициализируем подмодуль:

    git submodule deinit vendor/logger
    
  4. Удаляем подмодуль из индекса и файловой системы:

    git rm vendor/logger
    # Комментарий:
    # git rm обновит индекс и удалит каталог vendor/logger
    
  5. Редактируем .gitmodules (руками или командой) и удаляем блок:

    [submodule "vendor/logger"]
      path = vendor/logger
      url = git@github.com:some-org/logger.git
    
  6. Добавляем обновленный .gitmodules в индекс:

    git add .gitmodules
    
  7. Проверяем статус:

    git status
    # Должны быть изменения:
    #  - deleted: vendor/logger
    #  - modified: .gitmodules
    
  8. Фиксируем изменения:

    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 отвечает только за одну часть задачи: она деинициализирует подмодуль, удаляет его локальные настройки и «отвязывает» рабочий каталог.

Чтобы удалить подмодуль корректно:

  1. Деинициализируйте его с помощью git submodule deinit, при необходимости с флагом -f.
  2. Удалите путь подмодуля из индекса и файловой системы с помощью git rm.
  3. Очистите файл .gitmodules, удалив соответствующую секцию.
  4. Зафиксируйте изменения в коммите.

При таком подходе:

  • проект не будет содержать «висящих» ссылок на несуществующие подмодули;
  • другие разработчики не столкнутся с ошибками при работе с репозиторием;
  • история останется целостной, а старые коммиты — воспроизводимыми.

Обратите внимание на разницу между временной деинициализацией подмодуля и его полным удалением из проекта. git submodule deinit сама по себе не «стирает» подмодуль из истории и не убирает его из .gitmodules, а лишь делает первый шаг.


Частозадаваемые технические вопросы по теме и ответы

Вопрос 1. Как удалить подмодуль только локально не затрагивая репозиторий для других разработчиков

Если вы хотите убрать подмодуль только у себя, но не менять репозиторий:

  1. Выполните: bash git submodule deinit path/to/submodule
  2. Не трогайте .gitmodules и не используйте git rm.
  3. Файл .gitmodules и индекс не меняются, а у вас локально подмодуль деинициализирован.
    Позже его можно вернуть: bash git submodule update --init path/to/submodule

Вопрос 2. Как восстановить подмодуль после ошибочного удаления

Если вы уже удалили подмодуль (с коммитом), но хотите вернуть его:

  1. Найдите старый коммит, где подмодуль еще был, с помощью git log.
  2. Посмотрите содержимое .gitmodules в том коммите: bash git show <commit>:.gitmodules
  3. Восстановите нужный блок в текущем .gitmodules.
  4. Добавьте подмодуль заново: bash git submodule add <url> <path>
  5. Закоммитьте изменения.

Вопрос 3. Что делать если .gitmodules поврежден или удален но подмодуль еще есть в истории

Если .gitmodules случайно удален или испорчен:

  1. Восстановите его из прошлого коммита: bash git checkout HEAD~1 -- .gitmodules или из нужной версии, где он корректен.
  2. При необходимости отредактируйте.
  3. Добавьте в индекс и закоммитьте: bash git add .gitmodules git commit -m "Restore .gitmodules"

Вопрос 4. Как проверить какие подмодули сейчас активны после deinit

Чтобы увидеть, какие подмодули инициализированы:

  1. Посмотрите .git/config: bash cat .git/config # ищите секции [submodule "..."] с параметром active
  2. Используйте: bash git submodule status Подмодули, которые были деинициализированы, могут отображаться с префиксом - или как неинициализированные.

Вопрос 5. Можно ли полностью удалить историю подмодуля из основного репозитория

История подмодуля хранится в его собственном репозитории, а в основном хранятся только ссылки на коммиты. Полностью «вычистить» следы подмодуля из истории основного репозитория можно только переписав историю (например, с помощью git filter-repo):

  1. Используйте git filter-repo или git filter-branch, чтобы удалить путь подмодуля из всех коммитов.
  2. Это изменит историю, так что всем участникам проекта придется заново синхронизировать репозиторий.
  3. Такой подход стоит применять только в исключительных случаях.
Стрелочка влевоИнициализация подмодулей в Git - git submodule initКлонирование с подмодулями с помощью git clone --recursiveСтрелочка вправо

Постройте личный план изучения Git до уровня Middle — бесплатно!

Git — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Git

Открыть базу знаний

Лучшие курсы по теме

изображение курса

Основы Git

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий