Инициализация подмодулей в Git - git submodule init

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

Олег Марков

Введение

Подмодули в Git помогают подключать один репозиторий внутрь другого как зависимость. Представьте, что у вас есть основной проект и отдельный репозиторий с общими библиотеками. Вместо копирования файлов вы подключаете этот репозиторий как подмодуль. Так вы можете обновлять библиотеку независимо и при этом контролировать, какая именно версия используется в основном проекте.

Работа с подмодулями строится вокруг трёх базовых команд:

  • git submodule add — добавление нового подмодуля
  • git submodule init — инициализация подмодулей для текущего клона
  • git submodule update — загрузка содержимого подмодулей и переключение на нужные коммиты

В этой статье мы подробно разберём именно инициализацию подмодулей — что делает команда git submodule init, когда она нужна, чем отличается от git submodule update и как корректно выстраивать рабочий процесс с подмодулями, чтобы не сталкиваться с неожиданными ошибками.

Давайте разберёмся по шагам и на реальных примерах.

Что такое подмодуль в Git

Общая идея подмодулей

Подмодуль — это ссылку на другой Git-репозиторий, который "встраивается" в ваш основной репозиторий как подкаталог, но живёт своей жизнью:

  • у него свой собственный репозиторий и история коммитов
  • он может использоваться несколькими проектами
  • в основном репозитории хранится только информация о том, на какой коммит внутри подмодуля он ссылается

Смотрите, как это выглядит на практике:

  • Основной репозиторий: /my-app
  • Подмодуль: /my-app/libs/common (внутри лежит другой Git-репозиторий)

Главная особенность: в основном репозитории хранится не всё содержимое подмодуля, а только "указатель" на конкретный коммит подмодуля. При клонировании родительского репозитория вам нужно отдельно скачать содержимое подмодулей — именно здесь и появляется команда git submodule init.

Файлы, связанные с подмодулями

Когда вы используете подмодули, в корне репозитория появляется специальный служебный файл .gitmodules. В нём Git хранит конфигурацию подмодулей: пути, URL, имена.

Пример содержимого .gitmodules:

[submodule "libs/common"]
    path = libs/common        # Путь к подмодулю внутри основного репо
    url = https://github.com/example/common-lib.git  # URL удалённого репо

Кроме файла .gitmodules, Git также хранит настройки подмодулей в конфигурации репозитория (.git/config), и именно сюда попадает информация при выполнении git submodule init. Сейчас давайте посмотрим, что это за шаг и зачем он нужен.

Что делает команда git submodule init

Основное назначение git submodule init

Команда git submodule init выполняет инициализацию подмодулей для конкретного клона репозитория. Проще говоря, она:

  • читает файл .gitmodules
  • создаёт локальные записи конфигурации подмодулей в .git/config
  • подготавливает репозиторий к дальнейшему выполнению git submodule update

Важно: git submodule init НЕ скачивает содержимое подмодулей и НЕ переключает их на нужные коммиты. Она только настраивает конфигурацию.

Давайте посмотрим на базовый пример:

git clone https://github.com/example/my-app.git
cd my-app

# Инициализируем подмодули
git submodule init

# Загружаем содержимое подмодулей
git submodule update

Комментарий к шагам:

  • после git clone вы видите директории подмодулей, но они пустые или содержат только метаданные
  • команда git submodule init читает .gitmodules и регистрирует подмодули в локальной конфигурации
  • команда git submodule update уже использует эту конфигурацию, чтобы скачать данные и перейти на фиксированные коммиты

Где хранится информация после init

Когда вы выполняете git submodule init, Git переносит настройки из .gitmodules в локальный .git/config. Смотрите, как это выглядит.

Содержимое .gitmodules:

[submodule "libs/common"]
    path = libs/common
    url = https://github.com/example/common-lib.git

После git submodule init в .git/config появится примерно такое:

[submodule "libs/common"]
    url = https://github.com/example/common-lib.git  # URL подмодуля

Здесь я показываю только ключевой параметр url. При необходимости сюда могут добавляться и другие опции, если вы их настроите.

Зачем это нужно:

  • .gitmodules хранится в репозитории и версионируется
  • .git/config — локальная конфигурация, её можно изменять под конкретную машину (например, заменить HTTPS на SSH), не затрагивая общий репозиторий

git submodule init как раз делает этот перенос и создаёт базу для переопределений.

Почему init не всегда выполняется автоматически

Вы можете заметить, что во многих руководствах вместо связки команд

git submodule init
git submodule update

используют одну:

git submodule update --init

Этот вариант действительно выполняет и инициализацию, и загрузку содержимого. Но команда git submodule init остаётся полезной в случаях, когда вам нужно:

  • просто зарегистрировать подмодули, но не загружать их содержимое сейчас
  • изменить конфигурацию (например, URL подмодуля), прежде чем загружать его
  • инициализировать только часть подмодулей

Поэтому команда init — это отдельный осознанный шаг, который даёт больше гибкости.

Базовые сценарии использования git submodule init

Сценарий 1: Клонирование репозитория с подмодулями

Частый случай — вы клонируете проект, в котором уже настроены подмодули. Давайте разберём типичный рабочий процесс.

Шаг 1. Клонируем основной репозиторий:

git clone https://github.com/example/my-app.git
cd my-app

Шаг 2. Инициализируем подмодули:

git submodule init

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

  • Git читает файл .gitmodules
  • для каждого подмодуля добавляет секцию в .git/config
  • при необходимости вы можете скорректировать URL в .git/config (например, заменить HTTPS на SSH)

Шаг 3. Обновляем и загружаем подмодули:

git submodule update

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

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

Если вы хотите всё сделать одной командой, можно использовать:

git submodule update --init --recursive

Но мы сосредотачиваемся на явной инициализации, чтобы вы лучше понимали, что происходит на каждом шаге.

Сценарий 2: Инициализация только одного подмодуля

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

Пусть в .gitmodules у вас есть два подмодуля:

[submodule "libs/common"]
    path = libs/common
    url = https://github.com/example/common-lib.git

[submodule "libs/ui"]
    path = libs/ui
    url = https://github.com/example/ui-lib.git

Если вам пока нужна только библиотека common, вы можете инициализировать её по имени:

git submodule init libs/common
git submodule update libs/common

Важно: в git submodule init можно передавать не только путь, но и имя подмодуля. Обычно имя совпадает с тем, что в кавычках в .gitmodules ("libs/common"), а путь — это значение поля path. Как правило, проще указывать путь.

Пример с комментарием:

# Инициализируем конфигурацию только для подмодуля в каталоге libs/common
git submodule init libs/common

# Загружаем содержимое только этого подмодуля
git submodule update libs/common

Такой подход экономит время и трафик, если часть подмодулей вам не нужна.

Сценарий 3: Перенастройка URL перед загрузкой подмодулей

Иногда в .gitmodules прописан HTTPS-URL, а вы хотите использовать SSH (или наоборот). В этом случае удобно:

  1. выполнить git submodule init
  2. поменять URL в .git/config
  3. только потом вызвать git submodule update

Давайте разберём пример.

Предположим, в .gitmodules указано:

[submodule "libs/common"]
    path = libs/common
    url = https://github.com/example/common-lib.git

Вы выполняете:

git submodule init

Теперь в .git/config появляется запись:

[submodule "libs/common"]
    url = https://github.com/example/common-lib.git

Вы можете вручную изменить её, например так:

[submodule "libs/common"]
    url = git@github.com:example/common-lib.git

И только после этого выполнить:

git submodule update libs/common

Обратите внимание: изменение .git/config не затрагивает файл .gitmodules, то есть не влияет на других разработчиков, работающих с проектом. Это локальная настройка.

Отличие git submodule init от git submodule update

Логическая разница команд

Давайте ещё раз чётко разделим роли:

  • git submodule init — настраивает конфигурацию подмодулей в текущем клоне на основе .gitmodules
  • git submodule update — физически скачивает содержимое подмодулей и переключает их на нужные коммиты

Вы можете воспринимать это как два этапа:

  1. Настройка "что и откуда" (init)
  2. Загрузка "чего именно" (update)

Здесь я привожу небольшой пример, который покажет разницу на практике.

# После клонирования репозитория с подмодулями
git submodule init      # Настраиваем конфигурацию
git submodule update    # Клонируем и переключаем подмодули

Если вы попробуете выполнить только git submodule update без init, но при этом в .git/config ещё нет конфигурации подмодулей, Git просто не будет знать, откуда брать URL. В реальных проектах это чаще всего решается одной командой:

git submodule update --init

Но понимание разницы помогает в ситуациях с ручной настройкой, изменением URL и выборочной работой с подмодулями.

Зачем иногда удобно разделять init и update

Разделение на два шага полезно в таких случаях:

  • когда есть разные окружения (например, разработка, CI, staging, production) и вы хотите на каждом окружении переопределять URL подмодулей
  • когда часть подмодулей требует доступа по SSH, который не настроен на CI-сервере
  • когда размер подмодулей большой, и вы хотите загружать их содержимое "по требованию"

Смотрите, как может выглядеть скрипт развёртывания, использующий разделение:

# Инициализируем конфигурацию подмодулей
git submodule init

# Здесь мы можем программно изменить URL в .git/config,
# например, подставить зеркала или внутренние репозитории компании

# После всех корректировок загружаем подмодули
git submodule update --recursive

Комментарии в скрипте подсказывают, где удобно встроить дополнительные шаги по настройке.

Практическая работа с .gitmodules и git submodule init

Структура файла .gitmodules

Файл .gitmodules хранится в корне основного репозитория и участвует в версионировании. В нём описаны все подмодули, которые используются проектом.

Пример файла с двумя подмодулями:

[submodule "libs/common"]
    path = libs/common               # Путь к каталогу подмодуля
    url = https://github.com/example/common-lib.git  # URL удалённого репо

[submodule "libs/ui"]
    path = libs/ui
    url = https://github.com/example/ui-lib.git

Параметры:

  • submodule "имя" — логическое имя подмодуля, которое Git использует во внутренней конфигурации
  • path — относительный путь к каталогу, где будет располагаться подмодуль
  • url — адрес удалённого репозитория подмодуля

Когда вы вызываете git submodule init, Git использует этот файл, чтобы сформировать соответствующие секции в .git/config.

Как проверить, что инициализация прошла успешно

После выполнения git submodule init вы можете:

  1. Посмотреть конфигурацию подмодулей:
git config --file .gitmodules --name-only --get-regexp path
# Выводит пути подмодулей из .gitmodules

git config --file .git/config --name-only --get-regexp submodule
# Выводит секции подмодулей из локальной конфигурации
  1. Проверить статус подмодулей:
git submodule status

Типичный вывод:

-3a1b2c4 libs/common   # Подмодуль не инициализирован или не загружен
-7f9d8e1 libs/ui

Символ "-" в начале говорит о том, что подмодуль не инициализирован или не обновлён. После выполнения init + update вы увидите примерно такой формат:

 3a1b2c4 libs/common (heads/main)
 7f9d8e1 libs/ui (heads/main)

Теперь знак "-" исчез, а перед хешем стоит пробел — это означает, что подмодуль инициализирован и находится на нужном коммите.

Что происходит, если .gitmodules изменился

Представьте, что коллега добавил новый подмодуль и закоммитил обновлённый .gitmodules. Вы подтягиваете изменения:

git pull

В этот момент ваш локальный .git/config ещё не знает о новом подмодуле. Чтобы зарегистрировать его, вы снова выполняете:

git submodule init

Git посмотрит в .gitmodules, найдёт новые записи и добавит их в .git/config. Уже существующие подмодули повторно не пострадают — это операция "добавления того, чего ещё нет".

После этого вы можете загрузить содержимое нового подмодуля:

git submodule update

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

Расширенные приёмы использования git submodule init

Инициализация подмодулей в глубину (рекурсивно)

Во многих проектах подмодуль сам может содержать свои подмодули. Например:

  • основной репозиторий my-app использует подмодуль libs/common
  • подмодуль libs/common сам использует подмодуль vendor/logger

В таком случае вы можете инициализировать и обновить всю цепочку подмодулей рекурсивно:

git submodule update --init --recursive

Но иногда вам нужно именно разделить шаги. Тогда последовательность может быть такой:

# Инициализируем подмодули верхнего уровня
git submodule init

# Загружаем их содержимое вместе с их подмодулями
git submodule update --recursive

Или, если вы хотите вручную контролировать рекурсивную инициализацию, можно:

# Инициализируем все подмодули верхнего уровня
git submodule init

# Для каждого подмодуля переходим внутрь и выполняем те же команды
cd libs/common

# Инициализируем подмодули внутри подмодуля
git submodule init
git submodule update

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

  • такой ручной подход нужен редко, но помогает в нестандартных конфигурациях
  • чаще всего достаточно использовать флаг --recursive сразу в update

Частичная инициализация подмодулей для оптимизации

Если у вас монорепозиторий с большим количеством подмодулей, вы можете ускорить работу, инициализируя только нужные части.

Представим, что в .gitmodules у вас 10 подмодулей, но для вашей задачи нужны только 2. Тогда вы можете сделать так:

# Инициализируем только нужные подмодули по путям
git submodule init libs/common libs/ui

# Загружаем только их содержимое
git submodule update libs/common libs/ui

Обратите внимание:

  • git submodule init принимает список путей подмодулей
  • если вы случайно укажете путь, которого нет в .gitmodules, Git выдаст ошибку

Такой способ особенно полезен на CI, где вы хотите экономить время сборки.

Использование подмодулей при работе с форками

Частая ситуация: вы форкнули основной репозиторий, но подмодули в нём всё ещё ссылаются на оригинальные репозитории. Иногда это нормально, иногда вы хотите, чтобы подмодули тоже указывали на ваши форки.

Здесь практическая стратегия может выглядеть так:

  1. Клонируете форк основного репозитория
  2. Выполняете git submodule init
  3. Меняете URL подмодулей в .git/config (на свои форки)
  4. Выполняете git submodule update

Пример команд:

git clone git@github.com:my-org/my-app-fork.git
cd my-app-fork

# Инициализируем подмодули
git submodule init

# Меняем URL подмодуля libs/common на форк
git config submodule.libs/common.url git@github.com:my-org/common-lib-fork.git

# Загружаем подмодуль уже с новым URL
git submodule update libs/common

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

  • здесь мы не трогаем .gitmodules, чтобы не ломать исходную структуру проекта
  • все изменения остаются локальными в .git/config
  • такой подход удобен, если вы только тестируете свои модификации подмодулей

Типичные проблемы при инициализации подмодулей и как их решать

Проблема: подмодуль пустой после init

Ситуация: вы сделали git submodule init, заглянули в директорию подмодуля и увидели пустой каталог или только структуру без файлов.

Причина: init не скачивает содержимое подмодуля, он только регистрирует конфигурацию.

Решение:

# Инициализируем конфигурацию
git submodule init

# Загружаем содержимое и переключаем на нужный коммит
git submodule update

Если есть вложенные подмодули:

git submodule update --recursive

Проблема: неправильный или устаревший URL подмодуля

Ситуация: репозиторий подмодуля переехал, и URL в .gitmodules устарел. При выполнении git submodule update вы получаете ошибку клонирования.

Общая стратегия:

  1. Исправить URL в .gitmodules
  2. Повторно выполнить git submodule init (для синхронизации c .git/config)
  3. Обновить подмодуль

Пример:

# Открываем .gitmodules и меняем url:
# url = https://new-host.com/example/common-lib.git

# Синхронизируем конфиг подмодулей
git submodule init

# Либо более надёжно - используем sync
git submodule sync

# После этого снова пробуем обновить
git submodule update

Команда git submodule sync помогает синхронизировать URL между .gitmodules и .git/config. Если вы уже меняли URL вручную в .git/config, этот шаг особенно полезен.

Проблема: забыли выполнить init на новом клоне

Ситуация: вы клонировали репозиторий, перешли в каталог подмодуля, но видите странное состояние — нет истории, HEAD в detached-состоянии, файлы отсутствуют или ведут себя неожиданно.

Решение:

  1. Убедитесь, что подмодуль инициализирован и обновлён:
git submodule init
git submodule update
  1. Проверьте статус:
git submodule status

Если всё корректно, вы увидите хеши коммитов без дефиса в начале строки.

Проблема: подмодули не инициализируются автоматически на CI

На CI нередко забывают явно вызывать команды для подмодулей. В результате сборка падает, потому что часть кода отсутствует.

Минимальный набор действий на CI:

git submodule init
git submodule update --recursive

Либо одной командой:

git submodule update --init --recursive

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

  • если вам нужна гибкость (например, переопределение URL на CI), лучше разделять команды
  • если достаточно стандарта, можно использовать update --init

Заключение

Команда git submodule init — это важный шаг в рабочем процессе с подмодулями Git. Она не скачивает код, а настраивает конфигурацию подмодулей на основе файла .gitmodules, создавая записи в локальном .git/config. Именно после этого Git "понимает", какие подмодули есть в проекте и откуда их нужно загружать.

Ключевые моменты, которые стоит удержать:

  • init подготавливает локальный клон к работе с подмодулями, но не загружает их содержимое
  • update — отвечает за клонирование подмодулей и переключение их на нужные коммиты
  • связка init + настройка URL + update даёт гибкость при работе с разными окружениями, форками и зеркалами
  • частичная инициализация по путям помогает ускорить работу в больших репозиториях
  • повторный init безопасен и полезен после изменений в .gitmodules

Используя git submodule init осознанно, вы уменьшаете количество "магии" в поведении подмодулей и лучше контролируете, что происходит в вашем проекте при клонировании и обновлении зависимостей.

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

Вопрос 1. Как переинициализировать подмодуль, если я его удалил вручную из файловой системы

Если вы случайно удалили каталог подмодуля, но записи в Git остались, можно восстановиться так:

# Убедитесь, что конфигурация подмодуля есть
git submodule init

# Восстанавливаем содержимое каталога подмодуля
git submodule update --libs/common

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

  • git submodule init повторно не ломает конфигурацию, он просто убеждается, что записи есть
  • update заново клонирует и заполняет каталог подмодуля

Вопрос 2. Как перенести подмодуль в другой каталог и правильно переинициализировать

Шаги:

  1. Обновите путь в .gitmodules:
[submodule "libs/common"]
    path = libs/common-v2   # Новый путь
    url = https://github.com/example/common-lib.git
  1. Выполните:
git mv libs/common libs/common-v2        # Перемещаем каталог
git add .gitmodules libs/common-v2
git commit -m "Перемещен подмодуль libs/common в libs/common-v2"
  1. На новом клоне после pull выполните:
git submodule init
git submodule update

Git подхватит новый путь из .gitmodules и корректно инициализирует подмодуль.

Вопрос 3. Можно ли полностью отключить подмодуль, чтобы он не инициализировался на моей машине

Да, вы можете удалить запись о подмодуле из локального .git/config:

git config --unset submodule.libs/common.url

После этого git submodule init снова добавит эту запись из .gitmodules. Если вы хотите, чтобы подмодуль вообще не участвовал в вашей работе, просто не вызывайте init и удалите каталог:

rm -rf libs/common

Но помните, что при этом сборка проекта может не пройти, если этот код нужен.

Вопрос 4. Как инициализировать подмодуль в режиме только для чтения с использованием другого протокола

Можно использовать init, затем переопределить URL только для чтения в .git/config:

git submodule init

# Меняем URL на протокол только для чтения, например git
git config submodule.libs/common.url git://github.com/example/common-lib.git

git submodule update libs/common

В итоге вы не трогаете .gitmodules, но локально используете нужный протокол.

Вопрос 5. Как увидеть, какие подмодули ещё не были инициализированы

Можно сравнить список путей в .gitmodules и наличие конфигураций в .git/config:

# Список путей подмодулей из .gitmodules
git config --file .gitmodules --get-regexp path

# Список подмодулей, известных локальной конфигурации
git config --get-regexp submodule.*.url

Если подмодуль есть в .gitmodules, но нет в выводе второй команды, значит вы ещё не выполняли git submodule init для этого подмодуля.

Стрелочка влевоСтатус подмодулей - git submodule statusУдаление подмодуля - git submodule deinitСтрелочка вправо

Постройте личный план изучения 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 ₽
Подробнее

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