git submodules

Механизм включения одного Git-репозитория внутрь другого как вложенной зависимости с фиксацией конкретного коммита.

Зачем нужно

Submodule позволяет держать в проекте сторонний репозиторий (библиотеку, общие конфиги, шаблоны) с жёсткой привязкой к конкретному коммиту. Основной репозиторий отслеживает не файлы submodule, а лишь ссылку на точный коммит. Это даёт воспроизводимые сборки и возможность независимо обновлять зависимость.

Где используется

  • Монорепозиторий: общие компоненты между несколькими проектами
  • Включение сторонней библиотеки с фиксацией версии
  • Отдельный репозиторий с конфигурациями/темами (Hugo themes, dotfiles)
  • Большой проект разбит на субмодули для работы разных команд

Основной контент

Добавление submodule

# Добавить submodule
git submodule add https://github.com/org/shared-lib libs/shared

# Что произошло:
# 1. Создалась папка libs/shared/ с содержимым репозитория
# 2. Создан файл .gitmodules:
#    [submodule "libs/shared"]
#        path = libs/shared
#        url = https://github.com/org/shared-lib
# 3. В индекс добавлена запись-ссылка на коммит submodule

git commit -m "chore: добавить shared-lib как submodule"

Клонирование репозитория с submodules

# При обычном clone submodule-папки будут пустыми
git clone https://github.com/org/main-repo.git

# Инициализировать и загрузить submodules
cd main-repo
git submodule init
git submodule update

# Или одной командой при clone
git clone --recurse-submodules https://github.com/org/main-repo.git

Обновление submodule

# Обновить конкретный submodule до последнего коммита remote
git submodule update --remote libs/shared

# Обновить все submodules
git submodule update --remote

# Зафиксировать новую версию submodule в основном репо
git add libs/shared
git commit -m "chore(deps): обновить shared-lib до HEAD"

Работа внутри submodule

# Submodule находится в состоянии detached HEAD
cd libs/shared
git checkout main      # переключиться на ветку
git pull               # получить обновления
# ... внести изменения, закоммитить ...
git push

# Вернуться в основной репозиторий
cd ../..
git add libs/shared
git commit -m "chore(deps): обновить shared-lib"

Удаление submodule

# Корректное удаление submodule
git submodule deinit libs/shared     # очистить конфиг
git rm libs/shared                    # удалить из индекса и папку
# Удалить секцию из .gitmodules (git rm уже сделал это)
git commit -m "chore: удалить submodule shared-lib"

Просмотр submodules

# Список submodules и текущие коммиты
git submodule status

# Запустить команду в каждом submodule
git submodule foreach 'git pull origin main'

Частые ошибки

  • Забыть --recurse-submodules при clone — папки будут пустыми, проект не соберётся
  • Коммитить изменения только в submodule без обновления основного репо — другие разработчики будут смотреть на старую версию submodule
  • Detached HEAD в submodule — после git submodule update submodule находится в detached HEAD; для работы с ним переключись на ветку
  • Submodules как замена пакетным менеджерам — для npm/pip/cargo зависимостей используй соответствующие менеджеры; submodule — для исходного кода

Связанные темы

Ресурсы