Иконка подарка

Весенняя распродажа! Скидка 15% по промокоду

до 01.04.2026

Добавление подмодуля в Git - команда git submodule add

27 марта 2026
Автор

Олег Марков

Введение

В реальных проектах вам часто нужно использовать код из другого репозитория: общую библиотеку, модуль авторизации, UI-компоненты или, например, документацию. Один из способов аккуратно подключить такой внешний код — использовать подмодули Git.

Команда git submodule add позволяет добавить один Git‑репозиторий внутрь другого так, чтобы:

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

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

Что такое подмодуль в Git и когда он нужен

Общее представление

Смотрите, подмодуль — это по сути «ссылка» на другой репозиторий внутри вашего проекта. В файловой системе вы видите обычную папку, но Git хранит в родительском репозитории не содержимое этой папки, а только:

  • путь к подмодулю;
  • URL внешнего репозитория;
  • конкретный коммит, на который указывает подмодуль.

Это значит, что:

  • Подмодуль всегда «прибит» к конкретному коммиту внешнего репозитория, а не к ветке в целом.
  • Чтобы обновить подмодуль до свежей версии, нужно отдельно перейти внутрь подмодуля, подтянуть изменения и зафиксировать новый коммит подмодуля в основном репозитории.

Когда использовать подмодули

Подмодули хорошо подходят, если:

  1. У вас есть общая библиотека, которую используют несколько проектов, и вы хотите:

    • хранить ее отдельно;
    • но при этом фиксировать в каждом проекте конкретную версию этой библиотеки.
  2. Вы не хотите копировать внешний код внутрь проекта:

    • чтобы не дублировать историю;
    • чтобы можно было вести развитие этого кода отдельно.
  3. Вы хотите контролируемо обновлять зависимости:

    • не по последнему коммиту в ветке master/main;
    • а «поднимать» версию только когда вы готовы.

Но подмодули усложняют рабочий процесс, поэтому лучше использовать их там, где действительно нужно:

  • библиотечные репозитории;
  • общие инфраструктурные модули (CI‑скрипты, деплой‑конфигурации, шаблоны);
  • большие независимые компоненты (например, фронтенд и бэкенд как отдельные репозитории, но собранные в одном).

Теперь давайте перейдем к основной команде — git submodule add.

Базовый синтаксис команды git submodule add

Общий формат

Команда имеет несколько вариантов, но базовый синтаксис такой:

git submodule add <репозиторий> [путь]
# <репозиторий> — URL или относительный путь до репозитория подмодуля
# [путь] — путь в текущем репозитории, куда будет помещен подмодуль

Если путь не указать, Git возьмет имя репозитория из URL и создаст папку с этим именем.

Например, вы хотите добавить общую библиотеку в папку libs/common-lib:

git submodule add https://github.com/example/common-lib.git libs/common-lib
# common-lib.git — это репозиторий подмодуля
# libs/common-lib — папка в текущем проекте, где появится подмодуль

После этой команды происходит несколько вещей:

  1. В корне проекта создается (или обновляется) файл .gitmodules.
  2. В указанный путь клонируется внешний репозиторий.
  3. Основной репозиторий фиксирует ссылку на конкретный коммит подмодуля.

Как работает файл .gitmodules

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

Файл .gitmodules — это конфигурационный файл, где Git хранит информацию обо всех подмодулях проекта. Смотрите, как он выглядит:

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

Каждый подмодуль описан отдельным блоком submodule "<имя>".

Важно:

  • .gitmodules хранится в репозитории, его нужно добавлять в коммит.
  • Если этого не сделать, другие участники не узнают о подмодуле.

Что нужно закоммитить после git submodule add

Давайте разберем типичную последовательность действий:

git submodule add https://github.com/example/common-lib.git libs/common-lib

git status
# Здесь вы увидите:
#   - новый файл .gitmodules
#   - новую «папку» libs/common-lib (для Git это специальный тип — gitlink)

git add .gitmodules libs/common-lib
git commit -m "Добавлен подмодуль common-lib"

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

  • .gitmodules описывает конфиг подмодуля.
  • Папка libs/common-lib в индексе будет храниться как ссылка на конкретный коммит внешнего репозитория, а не как обычная папка с файлами.

Примеры добавления подмодулей

Пример 1. Добавление публичного репозитория с GitHub

Представим, что у вас есть основной проект, и вы хотите подключить внешний модуль:

# Переходим в корень основного проекта
cd /path/to/project

# Добавляем подмодуль из GitHub
git submodule add https://github.com/example/logger.git libs/logger
# logger.git — внешний репозиторий
# libs/logger — папка внутри проекта, куда попадет код подмодуля

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

  • в папке libs/logger — файлы подмодуля;
  • в корне — файл .gitmodules;
  • в git status — изменения и для .gitmodules, и для самого подмодуля.

Дальше:

git add .gitmodules libs/logger      # Добавляем конфиг и ссылку на подмодуль
git commit -m "Подключен подмодуль logger"

Пример 2. Добавление подмодуля по SSH

Если вы используете SSH‑доступ к Git (часто в приватных репозиториях), можно указать SSH‑URL:

git submodule add git@github.com:example/logger.git libs/logger
# Используем SSH-формат URL

Важно, чтобы у всех разработчиков, кто будет работать с этим проектом, был доступ по SSH к этому репозиторию. Иначе они не смогут инициализировать подмодуль.

Пример 3. Добавление локального репозитория как подмодуля

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

# Допустим, у вас есть:
# /projects/app        — основной проект
# /projects/libs/auth  — отдельный репозиторий с модулем авторизации

cd /projects/app

git submodule add ../libs/auth services/auth
# ../libs/auth — путь до локального репозитория
# services/auth — папка, куда поместится подмодуль

Git в .gitmodules все равно сохранит URL (часто перепишет его в относительный путь или в тот, что потом используется по сети).

Дополнительные параметры git submodule add

Команда git submodule add поддерживает ряд опций. Давайте разберем ключевые, которые реально полезны на практике.

Параметр -b / --branch — фиксация ветки по умолчанию

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

Синтаксис:

git submodule add -b main https://github.com/example/common-lib.git libs/common-lib
# -b main — говорим Git, что подмодуль ориентируется на ветку main

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

  • Git все равно зафиксирует конкретный коммит.
  • Но в .gitmodules будет записано:
[submodule "libs/common-lib"]
    path = libs/common-lib
    url = https://github.com/example/common-lib.git
    branch = main                   # Указана ветка по умолчанию

Это помогает, если вы планируете регулярно обновлять подмодуль по конкретной ветке.

Параметр --name — ручное имя подмодуля в .gitmodules

По умолчанию Git берет имя подмодуля из пути. Например:

git submodule add https://github.com/example/logger.git libs/logger

В .gitmodules появится:

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

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

git submodule add --name logger-lib https://github.com/example/logger.git libs/logger

Тогда:

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

Такое бывает удобно, если:

  • путь может со временем меняться;
  • но вы хотите сохранить логическое имя подмодуля.

Параметр --force — перезапись существующего пути

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

Пример:

git submodule add https://github.com/example/logger.git libs/logger
# Если в libs/logger уже есть папка, вы получите ошибку

В этом случае вы можете:

  • либо удалить папку вручную;
  • либо явно указать, что хотите перезаписать:
git submodule add --force https://github.com/example/logger.git libs/logger
# --force скажет Git игнорировать существующее содержимое

Используйте это осторожно, чтобы случайно не потерять нужные файлы.

Что происходит внутри Git при добавлении подмодуля

Когда вы добавляете подмодуль, Git не хранит все его файлы в коммите основного репозитория. Вместо этого в индексе и коммите появляется специальный тип записи — gitlink.

Упрощенно:

  • Для обычных файлов Git хранит blob‑объекты (содержимое файлов).
  • Для подмодуля Git хранит ссылку вида: «в этой папке лежит репозиторий, и он сейчас на коммите X».

Это видно по типу в некоторых командах (например, в git ls-tree).

Почему подмодуль не двигается сам при обновлении внешнего репозитория

Поскольку основному репозиторию сохранен конкретный SHA‑хеш коммита подмодуля, это жесткая фиксация.

Если в самом внешнем репозитории появятся новые коммиты, ваш основной проект:

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

Такой подход дает воспроизводимость сборок: вы всегда можете собрать проект с точно теми версиями, которые были когда-то зафиксированы.

Клонирование репозитория с подмодулями

Вариант 1. Сначала clone, потом init и update

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

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

Папки подмодулей появятся, но будут пустыми (или в виде специальных записей). Чтобы загрузить их содержимое, нужно выполнить:

git submodule init
# Регистрирует подмодули на основе файла .gitmodules

git submodule update
# Клонирует подмодули и переключает их на нужные коммиты

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

git submodule update --init --recursive
# --init — инициализирует
# --recursive — обходит вложенные подмодули

Вариант 2. Клонирование сразу с подмодулями

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

git clone --recurse-submodules https://github.com/example/app.git
# --recurse-submodules выполняет init + update для всех подмодулей

Здесь вы сразу получите:

  • основной репозиторий;
  • инициализированные подмодули с нужными версиями.

Работа с подмодулями после добавления

Переход внутрь подмодуля и обычная работа

Смотрите, подмодуль — это полноценный Git‑репозиторий, просто вложенный в другой. Поэтому все операции внутри него стандартные.

cd libs/common-lib

# Проверяем текущие ветки и состояние
git status
git branch

# Забираем обновления из удаленного репозитория
git fetch

# Переключаемся, например, на ветку main
git checkout main

Подмодуль ведет свою историю независимо от основного проекта.

Обновление версии подмодуля в основном репозитории

Давайте разберем, как обновить подмодуль до более свежей версии.

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

    cd libs/common-lib
    
  2. Получаем изменения и обновляемся, например, до последнего коммита в ветке main:

    git fetch
    git checkout main
    git pull origin main
    # Здесь вы обновляете сам подмодуль как обычный репозиторий
    
  3. Возвращаемся в корень основного проекта:

    cd ../..    # Возврат в корень, путь зависит от вашей структуры
    
  4. Проверяем изменения:

    git status
    # Вы увидите, что для подмодуля libs/common-lib сменился коммит
    
  5. Фиксируем это изменение:

    git add libs/common-lib
    git commit -m "Обновлена версия подмодуля common-lib"
    

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

  • В основном репозитории изменился только «хеш» подмодуля (ссылка на новый коммит).
  • Файлы подмодуля как таковые в основной истории не записываются.

Обновление всех подмодулей до последних коммитов веток

Если вы хотите обновить сразу все подмодули (например, до их текущих origin/HEAD), можно использовать:

git submodule update --remote
# Обновляет подмодули до последних коммитов отслеживаемых веток (из .gitmodules)

Если там указана ветка (через параметр branch в .gitmodules), Git ориентируется на нее.

Например, если в .gitmodules:

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

Тогда git submodule update --remote подтянет последний коммит из main.

Не забудьте потом закоммитить обновления:

git status
git add libs/common-lib   # и другие подмодули, если нужно
git commit -m "Обновлены подмодули до актуальных версий"

Изменения в подмодуле и их публикация

Если вы разрабатываете сам подмодуль

Иногда подмодуль — это ваш же репозиторий, и вы хотите в нем что-то изменить.

Последовательность действий:

  1. Переходите в папку подмодуля:

    cd libs/common-lib
    
  2. Вносите изменения в код, коммитите их:

    # Внесли изменения в файлы...
    
    git status
    git add .
    git commit -m "Добавлена новая функция логгера"
    git push origin main
    # Публикуете изменения в удаленный репозиторий подмодуля
    
  3. Возвращаетесь в основной репозиторий и фиксируете новый коммит подмодуля:

    cd ../..
    git status
    # Git покажет, что подмодуль libs/common-lib изменился (новый хеш)
    
    git add libs/common-lib
    git commit -m "Подмодуль common-lib обновлен до нового коммита"
    

Здесь важно не забывать:

  • сначала запушить изменения из подмодуля;
  • потом закоммитить ссылку на новый коммит в основном репозитории.

Иначе другие разработчики не смогут получить эти изменения, даже если обновят основной проект.

Если у вас нет прав записи в подмодуль

Если подмодуль — это внешний репозиторий, к которому у вас нет прав записи, вы можете:

  • форкнуть репозиторий;
  • использовать свой форк как подмодуль;
  • или предложить изменения через pull request в исходный репозиторий.

В таком случае URL подмодуля в .gitmodules может указывать, например, на ваш форк.

Изменение и переименование подмодулей

Изменение URL подмодуля

Представьте, что репозиторий перенесли, либо вы переключились с HTTPS на SSH. Менять URL подмодуля лучше через команды Git.

  1. Изменяем URL в конфигурации:

    git submodule set-url libs/common-lib git@github.com:example/common-lib.git
    # libs/common-lib — путь к подмодулю
    # git@github.com:... — новый URL
    
  2. Git обновит:

    • файл .gitmodules;
    • локальную конфигурацию .git/config.
  3. Фиксируем изменения:

    git add .gitmodules
    git commit -m "Обновлен URL подмодуля common-lib"
    

Перемещение подмодуля в другую папку

Если вам нужно перенести подмодуль в другую директорию, можно сделать это через Git, но последовательность немного сложнее, чем просто mv.

Подробнее:

  1. Останавливаем отслеживание текущего пути подмодуля:

    git rm --cached libs/common-lib
    # --cached — удаляет запись о подмодуле из индекса, не трогая файлы
    
  2. Перемещаем папку руками:

    mv libs/common-lib modules/common-lib
    # Переносим каталог подмодуля на новый путь
    
  3. Обновляем конфиг .gitmodules:

    # Можно отредактировать файл вручную
    # Было:
    # path = libs/common-lib
    # Стало:
    # path = modules/common-lib
    
  4. Сообщаем Git, что подмодуль теперь на новом пути:

    git add .gitmodules
    git add modules/common-lib
    git commit -m "Перемещен подмодуль common-lib в modules/common-lib"
    

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

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

Удаление подмодуля — частый источник путаницы, поэтому давайте сделаем это шаг за шагом.

Предположим, у вас есть подмодуль в libs/common-lib.

  1. Удаляем запись о подмодуле из индекса основного репозитория:

    git rm --cached libs/common-lib
    # --cached — Git перестает отслеживать подмодуль на этом пути
    
  2. Удаляем блок про подмодуль из .gitmodules:

    # Открываем .gitmodules и удаляем соответствующий блок:
    # [submodule "libs/common-lib"]
    #     path = libs/common-lib
    #     url = ...
    
  3. Опционально очищаем локальную конфигурацию Git:

    git config -f .git/config --remove-section submodule.libs/common-lib 2>/dev/null
    # Удаляем локальную секцию подмодуля, если она есть
    
  4. Удаляем физические файлы подмодуля (по желанию):

    rm -rf libs/common-lib
    # Удаляем папку подмодуля из файловой системы
    
  5. Фиксируем изменения:

    git add .gitmodules
    git commit -m "Удален подмодуль common-lib"
    

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

Типичные проблемы и подводные камни при использовании git submodule add

Подмодуль добавлен, но не закоммичен

Иногда разработчик выполняет:

git submodule add https://github.com/example/common-lib.git libs/common-lib

Но потом забывает добавить .gitmodules и сам путь подмодуля в коммит. В результате:

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

Проверка:

git status
# Убедитесь, что:
# - .gitmodules добавлен
# - путь к подмодулю добавлен

Решение:

git add .gitmodules libs/common-lib
git commit -m "Корректно добавлен подмодуль common-lib"

«Detached HEAD» в подмодуле

Когда вы клонируете проект с подмодулями, подмодуль часто оказывается в состоянии «detached HEAD» — то есть вы находитесь на конкретном коммите, не привязанном к ветке.

Проверить:

cd libs/common-lib
git status
# Git может показать, что вы не на ветке, а просто на коммите

Это нормально для подмодуля, если вы просто используете его как зависимость. Но если вы хотите там разрабатывать:

git checkout main
# или другую нужную ветку

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

  • Если вы сделаете коммиты в detached HEAD и не привяжете их к ветке, вы рискуете потерять эти изменения.

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

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

  • у него локально подмодуль на новом коммите;
  • у других — на старом;
  • чекаут основного репозитория не двигает подмодуль.

Решение:

  1. Разработчик, который обновлял подмодуль, должен:

    git add путь/к/подмодулю
    git commit -m "Обновлен подмодуль ..."
    git push
    
  2. Остальные выполняют:

    git pull
    git submodule update --init --recursive
    

Конфликты в .gitmodules

Если несколько людей редактировали .gitmodules (например, меняли URL или добавляли подмодули параллельно), возможны конфликты.

Решение:

  1. Открыть .gitmodules, аккуратно разрешить конфликт.
  2. Убедиться, что для каждого подмодуля:

    • корректный path;
    • правильный url;
    • при необходимости — branch.
  3. Сохранить файл и выполнить:

    git add .gitmodules
    git commit
    

Рекомендации по использованию git submodule add в реальных проектах

Когда подмодуль — хороший выбор

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

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

Пример:

  • общий модуль логирования;
  • общие компоненты интерфейса для нескольких приложений;
  • инфраструктурный репозиторий с CI‑скриптами.

Когда лучше рассмотреть альтернативы

Подумаете, нужен ли вам действительно git submodule add, если:

  • зависимость — это библиотека, доступная через пакетный менеджер (Go modules, npm, Maven, Composer и т.д.);
  • достаточно указать версию в файле зависимостей, а не тянуть весь Git‑репозиторий как подмодуль.

Также есть альтернативы:

  • git subtree — когда вы хотите включить внешний репозиторий в историю основного;
  • копирование кода (в редких случаях).

Организационные моменты

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

  • использовать понятные пути (например, libs/имя или modules/имя);
  • договориться в команде, кто и когда обновляет подмодули;
  • описать в README проекта инструкции:

    • как клонировать репозиторий с подмодулями;
    • какие команды запускать для обновления.

Пример блока в README:

# Клонирование проекта вместе с подмодулями
git clone --recurse-submodules <url>

# Если проект уже склонирован
git submodule update --init --recursive

# Обновление подмодулей до актуальных версий
git submodule update --remote --recursive

Это сильно снижает количество вопросов у новых участников команды.


Подмодули в Git — мощный инструмент, который позволяет гибко организовывать код в нескольких репозиториях, но требует аккуратного обращения. Команда git submodule add — точка входа в эту функциональность. Если вы будете:

  • всегда коммитить .gitmodules и ссылки на подмодули;
  • внимательно относиться к обновлениям и состоянию подмодулей;
  • документировать правила в команде;

то подмодули станут удобным и предсказуемым инструментом, а не источником постоянных проблем.

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

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

Полностью автоматизировать это в чистом Git нельзя — подмодуль по определению фиксируется на коммите. Но можно упростить процесс:

  1. В .gitmodules укажите ветку:

    [submodule "libs/common-lib"]
        path = libs/common-lib
        url = https://github.com/example/common-lib.git
        branch = main
    
  2. Для обновления используйте:

    git submodule update --remote libs/common-lib
    
  3. Закоммитьте обновление подмодуля в основной репозиторий.

Вопрос 2. Как добавить подмодуль, но использовать относительный URL, чтобы репозитории работали и на разных серверах?

Можно сразу задать относительный URL:

git submodule add ../common-lib.git libs/common-lib
# Относительный путь к репозиторию относительно текущего

Git сохранит его в .gitmodules. Это удобно, если основной репозиторий и подмодуль лежат рядом в структуре Git‑сервера и мигрируют вместе.

Вопрос 3. Как сделать вложенные подмодули (подмодуль внутри подмодуля) и не запутаться?

Последовательность:

  1. Внутри подмодуля выполняете git submodule add как обычно.
  2. В корне основного репозитория при клонировании и обновлении всегда используйте:

    git submodule update --init --recursive
    # --recursive захватывает вложенные подмодули
    
  3. Обязательно коммитьте .gitmodules и изменения ссылок на подмодули на каждом уровне.

Вопрос 4. Как временно изменить URL подмодуля только для себя (например, на свой форк)?

Используйте локальную конфигурацию:

git config submodule.libs/common-lib.url git@github.com:myfork/common-lib.git
# Меняется только в .git/config, не в .gitmodules

Так вы измените источник подмодуля только локально, не затрагивая остальных участников.

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

  1. Убедитесь, что запись о подмодуле осталась в .gitmodules и в индексе:

    git status
    
  2. Восстановите содержимое подмодуля:

    git submodule update --init путь/к/подмодулю
    # Git заново клонирует и переключит подмодуль на нужный коммит
    

Если .gitmodules был поврежден, восстановите его из истории:

git checkout HEAD -- .gitmodules
Стрелочка влевоКлонирование с подмодулями с помощью 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 ₽
Подробнее

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