Олег Марков
Статус подмодулей - git submodule status
Введение
Работа с подмодулями Git часто вызывает вопросы даже у опытных разработчиков. Подмодуль — это по сути отдельный Git‑репозиторий, «встроенный» внутрь другого репозитория. Они удобны, когда нужно переиспользовать общий код между несколькими проектами: библиотеку, набор скриптов, дизайн‑систему и так далее.
Но как только подмодулей становится несколько, сразу встает вопрос: в каком они состоянии сейчас, совпадает ли то, что у вас локально, с тем, что зафиксировано в основном репозитории, не забыли ли вы обновить версии?
Вот здесь и становится полезной команда git submodule status. Она отвечает на базовый, но очень важный вопрос — какой конкретно коммит сейчас используется в каждом подмодуле и соответствует ли он тому, что ожидает основной репозиторий.
В этой статье вы разберетесь:
- что именно показывает git submodule status;
- как читать его символы и вывод;
- как отличить «чистый» подмодуль от измененного или неинициализированного;
- как использовать статус подмодулей в повседневной работе и CI;
- какие типичные проблемы возникают и как их диагностировать по статусу.
Что такое подмодуль и почему важен его статус
Кратко о подмодулях
Подмодуль Git — это ссылка на другой репозиторий, зафиксированная в определенном коммите. В основном репозитории хранится не содержимое подмодуля, а:
- ссылка на конкретный коммит внешнего репозитория;
- настройки в файле
.gitmodules(URL, ветка по умолчанию, путь).
Когда вы клонируете репозиторий с подмодулями, по умолчанию вы получаете только «пустые папки» подмодулей, без их содержимого (если не используете специальные опции). Инициализация, обновление и проверка состояния подмодулей — это отдельные шаги.
Почему нужен статус подмодулей
Команда git submodule status позволяет:
- понять, инициализирован ли подмодуль;
- увидеть текущий коммит подмодуля;
- понять, соответствует ли он коммиту, зафиксированному в основном репозитории;
- заметить локальные изменения внутри подмодуля (не закомиченные или не запушенные);
- увидеть, если подмодуль «ушел вперед» или «отстал» от зафиксированной версии.
Смотрите, я покажу вам, как это выглядит в типичном случае.
Базовое использование git submodule status
Простейший вызов команды
Самый простой вариант:
git submodule status
Давайте разберемся, что вы увидите в выводе. Пример:
$ git submodule status
3a5f9b7f2e3c4d8e9f0a1b2c3d4e5f6a7b8c9d0 libs/my-lib
-4e8c9b7f1a2d3c4e5f6a7b8c9d0e1f2a3b4c5d6 tools/scripts
+8c7b6a5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9 common/shared-lib (heads/main)
Каждая строка описывает один подмодуль и состоит из нескольких частей:
- Первый символ (
-,+, пробел илиU) — индикатор состояния. - Хеш коммита (обычно сокращенный SHA‑1/SHA‑256).
- Путь к подмодулю в вашем репозитории.
- Опциональные комментарии в скобках (например, текущая ветка или информация о конфликте).
Теперь давайте детально разберем эти элементы.
Индикаторы состояния подмодуля
Пробел перед хешем
Если строка начинается с пробела, все хорошо:
3a5f9b7f2e3c4d8e9f0a1b2c3d4e5f6a7b8c9d0 libs/my-lib
Это означает:
- подмодуль инициализирован;
- текущий коммит подмодуля совпадает с тем, что зафиксирован в основном репозитории;
- нет несохраненных локальных изменений (с точки зрения верхнего репозитория это «идеальное состояние»).
Вы можете считать такой подмодуль полностью синхронизированным.
Знак «минус» - — неинициализированный подмодуль
-4e8c9b7f1a2d3c4e5f6a7b8c9d0e1f2a3b4c5d6 tools/scripts
Минус говорит, что:
- подмодуль объявлен в
.gitmodules; - в индекс основного репозитория записан указанный коммит;
- но содержимое подкаталога подмодуля не инициализировано (репозиторий подмодуля не клонирован или не выкачан).
Чаще всего вы увидите такое состояние сразу после клонирования родительского репозитория без рекурсивного захвата подмодулей.
Чтобы привести подмодуль в рабочее состояние, выполните:
# Инициализация конфигурации подмодулей (на основе .gitmodules)
git submodule init
# Загрузка нужных коммитов подмодулей
git submodule update
Или одним шагом:
git submodule update --init --recursive
Комментарий:
# --init инициализирует подмодуль, если он еще не настроен
# --recursive рекурсивно инициализирует подмодули внутри подмодулей
После этого статус обычно сменится с - на пробел.
Знак «плюс» + — рассинхронизация с ожидаемым коммитом
+8c7b6a5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9 common/shared-lib (heads/main)
Плюс означает:
- текущий коммит подмодуля отличается от того, который зафиксирован в основном репозитории;
- вы либо переключили подмодуль на другой коммит/ветку;
- либо обновили подмодуль, но еще не закоммитили новый хеш в родительском репозитории.
Чаще всего это нормальная ситуация: вы обновили подмодуль и собираетесь зафиксировать новую версию.
Чтобы убедиться, что все сделано осознанно, вы можете:
cd common/shared-lib
# Посмотреть ветку и текущий коммит
git status
git log -1
cd ../..
# Зафиксировать новый указатель на подмодуль в основном репозитории
git add common/shared-lib
git commit -m "Обновить версию подмодуля common/shared-lib"
После коммита (и если другие разработчики выполнят git submodule update) статус для этого подмодуля снова станет «чистым» (пробел).
Буква U — конфликт подмодуля при слиянии
U3a5f9b7f2e3c4d8e9f0a1b2c3d4e5f6a7b8c9d0 libs/my-lib
U показывает, что во время merge или rebase возник конфликт:
- основной репозиторий не смог автоматически выбрать, к какому коммиту подмодуля нужно прикрепиться;
- вам нужно вручную решить, какая версия подмодуля считается верной.
Обычно процесс выглядит так:
# Переходим в подмодуль
cd libs/my-lib
# Смотрим историю и доступные коммиты
git log --oneline --graph --decorate --all
# Выбираем нужный коммит
git checkout <нужный-коммит-или-ветку>
cd ../..
# Фиксируем выбранное состояние подмодуля в основном репозитории
git add libs/my-lib
git commit
После этого индикатор U исчезнет.
Структура строки статуса
Разберем пример строки целиком:
+8c7b6a5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9 common/shared-lib (heads/main)
+— подмодуль отличается от зафиксированного в родительском репо;8c7b6a5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9— текущий коммит подмодуля;common/shared-lib— путь, где расположен подмодуль;(heads/main)— дополнительная информация:- показывает, что текущий коммит совпадает с головой ветки
mainвнутри подмодуля.
- показывает, что текущий коммит совпадает с головой ветки
Фраза (heads/main) особо полезна, когда вы хотите убедиться, что подмодуль «сидит» на нужной ветке, а не на каком‑то случайном коммите.
Практические сценарии работы со статусом подмодулей
Проверка после клонирования репозитория
Частая ситуация: вы клонировали проект с подмодулями, но не уверены, все ли подтянулось.
git clone https://example.com/your-project.git
cd your-project
git submodule status
Если вы увидите много строк с -:
-4e8c9b7f1a2d3c4e5f6a7b8c9d0e1f2a3b4c5d6 libs/core
-9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0 thirdparty/img-tools
Это означает, что подмодули объявлены, но еще не инициализированы.
Решение:
# Инициализировать и обновить все подмодули
git submodule update --init --recursive
# Проверить статус снова
git submodule status
Теперь вы должны увидеть строки с пробелом (если все подтянулось корректно).
Контроль перед коммитом или пушем
Полезная практика — проверять статус подмодулей перед пушем:
git submodule status
На что стоит обратить внимание:
- есть ли подмодули с
+— если да, вы обновляли их осознанно? - есть ли подмодули с
-— если да, не забыли ли вы добавить их в проект или проинициализировать? - если вы видите конфликт
U— его нужно обязательно решить до пуша.
Иногда удобно сделать alias, который одновременно показывает статус основного репозитория и подмодулей. Например, в .gitconfig:
[alias]
st = status -sb
st-all = "!git status -sb && echo '--- submodules ---' && git submodule status"
Комментарий:
# Теперь можно вызвать
git st-all
# Сначала покажется статус основного репо, затем статус всех подмодулей
Отладка «странного» поведения: код не тот, что ожидался
Бывает, вы запускаете приложение и видите, что какая‑то библиотека ведет себя «по‑старому» или наоборот, использует новый код, который вы еще не ожидали. Часто это связано с тем, что подмодуль:
- не обновился до нужного коммита;
- или был случайно переключен на другую ветку.
Смотрите, как можно это проверить:
git submodule status
Если вы видите + или (heads/...) не той ветки, которую ожидали, это уже подсказка.
Дальше:
cd path/to/submodule
# Проверяем, какая ветка активна
git status
# Сравниваем с удаленным репо
git fetch
git log --oneline --decorate --graph --all
Если нужно привести подмодуль к нужному состоянию:
# Обновляем до того коммита, который записан в родительском репо
cd /path/to/parent
git submodule update path/to/submodule
Комментарий:
# git submodule update
# - выкачивает тот коммит, на который ссылается родительский репозиторий
# - сбрасывает рабочее состояние подмодуля к этому коммиту (detached HEAD)
После этого git submodule status снова покажет «чистое» состояние.
Опции и режимы работы git submodule status
Режим вывода для конкретных путей
Вы можете запросить статус только некоторых подмодулей, указав путь:
git submodule status libs/my-lib thirdparty/http-client
Это удобно в больших репозиториях с десятками подмодулей, когда вы работаете только с одной или двумя библиотеками.
Вывод рекурсивно для вложенных подмодулей
Если у вас есть подмодули внутри подмодулей, имеет смысл использовать рекурсивный статус:
git submodule status --recursive
Так вы увидите:
- состояние подмодулей первого уровня;
- и состояние подмодулей, которые находятся внутри них.
Например:
$ git submodule status --recursive
3a5f9b7 libs/sdk
9c8d7e4 libs/sdk/vendor/json-lib
-4a3b2c1 tools/integration-tests
Комментарий:
# Обратите внимание на отступы:
# - первая строка: подмодуль первого уровня
# - вторая строка: подмодуль внутри libs/sdk (с отступом)
Опция --cached (статус по индексу)
По умолчанию git submodule status показывает фактическое состояние в файловой системе. Но иногда важно увидеть состояние по индексу (то, что готово к коммиту).
Для этого используйте:
git submodule status --cached
Вывод в этом случае:
- основан на тех хешах, которые уже добавлены в индекс родительского репозитория;
- не зависит от того, что у вас сейчас реально выкачано в подкаталогах подмодулей.
Смотрите на пример:
# Вы обновили подмодуль, но еще не добавили его в индекс
git submodule status
# -> +<hash> libs/my-lib
git add libs/my-lib
git submodule status
# -> <hash> libs/my-lib (с пробелом, все чисто)
git submodule status --cached
# -> <тот же hash> libs/my-lib
Опция --cached полезна, когда вы хотите проверить состояние подмодулей именно в контексте будущего коммита.
Опция --summary (краткие изменения подмодуля)
Хотя основная тема статьи — именно команда git submodule status, часто разработчики хотят не просто видеть хеш, но и понять, что изменилось в подмодуле.
Для этого используется связанная команда:
git submodule summary
Но у git submodule status есть небольшое, но полезное сочетание: можно использовать статус вместе с diff, чтобы увидеть изменения по подмодулям.
Пример:
# Посмотреть, какие подмодули изменились относительно origin/main
git diff --submodule=log origin/main
Комментарий:
# --submodule=log говорит Git
# - выводить краткое резюме изменений внутри подмодулей
# - показывать, от какого до какого коммита произошел переход
В результате вы увидите блоки вида:
Submodule libs/my-lib 3a5f9b7..8c7b6a5 (2):
+ Исправлен парсер конфигурации
+ Добавлены новые тесты
Это хорошее дополнение к информации, которую вы видите в git submodule status.
Типичные рабочие сценарии и пошаговые инструкции
Сценарий 1. Проинициализировать подмодули после клонирования
Давайте разберемся на конкретном примере.
Клонируете репозиторий:
git clone https://example.com/app.git cd appПроверяете статус подмодулей:
git submodule statusВидите:
-4e8c9b7 libs/core -9a8b7c6 thirdparty/jsonИнициализируете и обновляете:
git submodule update --init --recursiveСнова проверяете:
git submodule statusТеперь вывод:
4e8c9b7 libs/core 9a8b7c6 thirdparty/json
Все подмодули готовы к работе.
Сценарий 2. Обновить подмодуль до новой версии и зафиксировать ее
Представим, что вы хотите обновить библиотеку, подключенную как подмодуль.
Проверяете текущий статус:
git submodule statusПереходите в каталог подмодуля:
cd libs/coreОбновляете код подмодуля:
git fetch origin # Например, переключаетесь на последний коммит ветки main git checkout origin/main # Либо # git checkout main # git pullВозвращаетесь в родительский репозиторий:
cd ../..Смотрите статус:
git submodule statusТеперь строка для
libs/coreбудет начинаться с+, потому что текущий коммит подмодуля отличается от того, что зафиксирован в основном репо.Фиксируете обновление подмодуля:
git add libs/core git commit -m "Обновить подмодуль libs/core до последней версии main"После этого:
git submodule statusВывод снова покажет «чистый» статус (пробел).
Сценарий 3. Решение конфликта подмодуля при merge
Покажу вам, как это реализовано на практике, когда два разработчика изменили версию одного и того же подмодуля в разных ветках.
Вы делаете merge:
git merge feature/new-apiПолучаете конфликт:
CONFLICT (submodule): Merge conflict in libs/api-clientПроверяете статус:
git submodule statusВидите:
U3a5f9b7 libs/api-clientПереходите в подмодуль:
cd libs/api-clientСмотрите историю:
git log --oneline --graph --decorate --allЗдесь вы ищете, к какому коммиту нужно привести подмодуль (иногда это новая ветка, иногда конкретный тег).
Выбираете нужный коммит:
git checkout <нужный-коммит-или-ветка>Возвращаетесь в корень проекта:
cd ../..Отмечаете конфликт как решенный, добавив подмодуль:
git add libs/api-client git commit
Теперь статус вернется к нормальному состоянию.
Сценарий 4. Автоматическая проверка статуса подмодулей в CI
Часто полезно в CI гарантировать, что:
- все подмодули инициализированы;
- нет «забытых» плюсиков, не зафиксированных в основном репозитории.
Простейший скрипт проверки может выглядеть так:
#!/usr/bin/env bash
set -e
# Проверяем, что все подмодули инициализированы и без рассинхронизаций
if git submodule status | grep -E '^[+-]'; then
echo "Обнаружены неинициализированные или несинхронизированные подмодули"
echo "Пожалуйста, выполните:"
echo " git submodule update --init --recursive"
echo "и закоммитьте новые версии подмодулей при необходимости"
exit 1
fi
echo "Все подмодули в консистентном состоянии"
Комментарий:
# grep -E '^[+-]'
# - ищет строки, начинающиеся с + или -
# - если такие есть, значит либо подмодуль не инициализирован (-),
# либо его версия не совпадает с той, что в индексе (+)
Этот скрипт можно запускать в CI‑пайплайне перед сборкой или тестами.
Типичные проблемы и их диагностика по статусу
Проблема 1. «У меня нет нужного кода, но у коллег работает»
Часто корень проблемы — в подмодулях. Алгоритм:
Проверьте статус:
git submodule statusЕсли видите
-— подмодуль не инициализирован:git submodule update --init --recursiveЕсли видите
+— версии не совпадают:# Привести к версии, записанной в основном репо git submodule update
После этого ваш код будет соответствовать тому, что использует команда.
Проблема 2. Неожиданные изменения подмодуля в git status
Иногда вы выполняете git status в родительском репо и видите:
modified: libs/core (modified content)
Это говорит о том, что:
- внутри подмодуля вы что‑то поменяли (новые коммиты или незакоммиченные изменения);
- с точки зрения родительского репо подмодуль теперь указывает на другой коммит.
Проверьте:
git submodule status
Вы увидите + и, возможно, комментарии внутри подмодуля.
Если изменения в подмодуле вам не нужны:
# Восстановить подмодуль к версии из родительского репо
git submodule update libs/core
Если нужны:
# Закоммитить их в подмодуле
cd libs/core
git commit -am "Ваше сообщение"
git push
cd ../..
# Обновить ссылку на подмодуль в родительском репо
git add libs/core
git commit -m "Обновить libs/core до новой версии"
Проблема 3. Подмодуль пустой, хотя должен содержать код
Ситуация:
- папка подмодуля существует;
- но внутри нет файлов или они не соответствуют ожиданиям.
Чаще всего это значит, что вы забыли выполнить update.
Порядок действий:
# Проверяем статус
git submodule status
# Инициализируем и обновляем при необходимости
git submodule update --init --recursive
Если и после этого внутри пусто, проверьте:
- URL подмодуля в
.gitmodules; - доступность репозитория (права, SSH‑ключи и т.п.).
Заключение
Команда git submodule status — это простой, но очень полезный инструмент для контроля состояния подмодулей. Она позволяет:
- быстро понять, какие подмодули инициализированы, а какие нет;
- увидеть, где текущий коммит подмодуля отличается от ожидаемого;
- вовремя обнаружить конфликты и рассинхронизацию;
- использовать автоматизированные проверки в CI, чтобы гарантировать консистентность версий.
Ключевые моменты, которые важно помнить:
- пробел в начале строки — подмодуль в чистом состоянии, все совпадает;
-— подмодуль не инициализирован в рабочем каталоге;+— текущий коммит подмодуля отличается от того, что записан в индексе родительского репозитория;U— конфликт при слиянии, требующий ручного решения;- опции
--recursiveи--cachedпомогают лучше контролировать статус подмодулей в сложных проектах.
Если вы будете регулярно пользоваться git submodule status и понимать, что означают его символы, работа с подмодулями станет более предсказуемой и управляемой.
Частозадаваемые технические вопросы по теме
Вопрос 1. Как узнать, на какой ветке сейчас находится подмодуль, если статус показывает только хеш?
Ответ:
Выполните:
cd path/to/submodule git status- В выводе вы увидите текущую ветку (например,
On branch main). Если подмодуль в состоянии detached HEAD, используйте:
git branch --contains HEADчтобы понять, к каким веткам относится текущий коммит.
Вопрос 2. Как сделать так, чтобы подмодуль всегда автоматически обновлялся до последнего коммита ветки?
Ответ:
Git по умолчанию закрепляет подмодуль за конкретным коммитом, а не «живой» веткой. Но можно настроить поведение обновления:
В
.gitmodulesдобавьте:[submodule "libs/core"] path = libs/core url = git@example.com:libs/core.git branch = mainПри обновлении используйте:
git submodule update --remoteТогда подмодуль подтянет последний коммит указанной ветки.
Вопрос 3. Как увидеть, какие именно изменения произошли в подмодуле при переходе от одной версии к другой?
Ответ:
Для краткого резюме:
git diff --submodule=log <old-ref> <new-ref>Для детального просмотра внутри самого подмодуля:
cd path/to/submodule git log --oneline <old-commit>..<new-commit> git diff <old-commit>..<new-commit>
Вопрос 4. Почему git submodule status показывает старый хеш, хотя в удаленном репозитории подмодуля уже есть новые коммиты?
Ответ:
Статус подмодуля отражает не «последнее состояние внешнего репозитория», а тот конкретный коммит, на который указывает родительский репозиторий. Чтобы обновить:
Зайдите в подмодуль и подтяните новые коммиты:
cd path/to/submodule git fetch git checkout origin/mainВернитесь в родительский репозиторий и зафиксируйте новое состояние:
cd ../.. git add path/to/submodule git commit -m "Обновить подмодуль до новой версии"
Вопрос 5. Как удалить подмодуль полностью, чтобы он исчез и из статуса, и из конфигурации?
Ответ:
Шаги:
Удалите подмодуль из индекса и рабочего каталога:
git rm -f path/to/submodule- Удалите соответствующий блок из файла
.gitmodules. - При необходимости удалите настройки подмодуля из
.git/config. Закоммитьте изменения:
git commit -m "Удалить подмодуль path/to/submodule"
После этого git submodule status перестанет показывать удаленный подмодуль.
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

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