Статус подмодулей - git submodule status

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

Олег Марков

Введение

Работа с подмодулями 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)

Каждая строка описывает один подмодуль и состоит из нескольких частей:

  1. Первый символ (-, +, пробел или U) — индикатор состояния.
  2. Хеш коммита (обычно сокращенный SHA‑1/SHA‑256).
  3. Путь к подмодулю в вашем репозитории.
  4. Опциональные комментарии в скобках (например, текущая ветка или информация о конфликте).

Теперь давайте детально разберем эти элементы.

Индикаторы состояния подмодуля

Пробел перед хешем

Если строка начинается с пробела, все хорошо:

 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. Проинициализировать подмодули после клонирования

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

  1. Клонируете репозиторий:

    git clone https://example.com/app.git
    cd app
    
  2. Проверяете статус подмодулей:

    git submodule status
    

    Видите:

    -4e8c9b7 libs/core
    -9a8b7c6 thirdparty/json
    
  3. Инициализируете и обновляете:

    git submodule update --init --recursive
    
  4. Снова проверяете:

    git submodule status
    

    Теперь вывод:

     4e8c9b7 libs/core
     9a8b7c6 thirdparty/json
    

Все подмодули готовы к работе.

Сценарий 2. Обновить подмодуль до новой версии и зафиксировать ее

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

  1. Проверяете текущий статус:

    git submodule status
    
  2. Переходите в каталог подмодуля:

    cd libs/core
    
  3. Обновляете код подмодуля:

    git fetch origin
    
    # Например, переключаетесь на последний коммит ветки main
    git checkout origin/main
    # Либо
    # git checkout main
    # git pull
    
  4. Возвращаетесь в родительский репозиторий:

    cd ../..
    
  5. Смотрите статус:

    git submodule status
    

    Теперь строка для libs/core будет начинаться с +, потому что текущий коммит подмодуля отличается от того, что зафиксирован в основном репо.

  6. Фиксируете обновление подмодуля:

    git add libs/core
    git commit -m "Обновить подмодуль libs/core до последней версии main"
    
  7. После этого:

    git submodule status
    

    Вывод снова покажет «чистый» статус (пробел).

Сценарий 3. Решение конфликта подмодуля при merge

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

  1. Вы делаете merge:

    git merge feature/new-api
    
  2. Получаете конфликт:

    CONFLICT (submodule): Merge conflict in libs/api-client
    
  3. Проверяете статус:

    git submodule status
    

    Видите:

    U3a5f9b7 libs/api-client
    
  4. Переходите в подмодуль:

    cd libs/api-client
    
  5. Смотрите историю:

    git log --oneline --graph --decorate --all
    

    Здесь вы ищете, к какому коммиту нужно привести подмодуль (иногда это новая ветка, иногда конкретный тег).

  6. Выбираете нужный коммит:

    git checkout <нужный-коммит-или-ветка>
    
  7. Возвращаетесь в корень проекта:

    cd ../..
    
  8. Отмечаете конфликт как решенный, добавив подмодуль:

    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. «У меня нет нужного кода, но у коллег работает»

Часто корень проблемы — в подмодулях. Алгоритм:

  1. Проверьте статус:

    git submodule status
    
  2. Если видите - — подмодуль не инициализирован:

    git submodule update --init --recursive
    
  3. Если видите + — версии не совпадают:

    # Привести к версии, записанной в основном репо
    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. Как узнать, на какой ветке сейчас находится подмодуль, если статус показывает только хеш?

Ответ:

  1. Выполните:

    cd path/to/submodule
    git status
    
  2. В выводе вы увидите текущую ветку (например, On branch main).
  3. Если подмодуль в состоянии detached HEAD, используйте:

    git branch --contains HEAD
    

    чтобы понять, к каким веткам относится текущий коммит.

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

Ответ:

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

  1. В .gitmodules добавьте:

    [submodule "libs/core"]
        path = libs/core
        url = git@example.com:libs/core.git
        branch = main
    
  2. При обновлении используйте:

    git submodule update --remote
    

    Тогда подмодуль подтянет последний коммит указанной ветки.

Вопрос 3. Как увидеть, какие именно изменения произошли в подмодуле при переходе от одной версии к другой?

Ответ:

  1. Для краткого резюме:

    git diff --submodule=log <old-ref> <new-ref>
    
  2. Для детального просмотра внутри самого подмодуля:

    cd path/to/submodule
    git log --oneline <old-commit>..<new-commit>
    git diff <old-commit>..<new-commit>
    

Вопрос 4. Почему git submodule status показывает старый хеш, хотя в удаленном репозитории подмодуля уже есть новые коммиты?

Ответ:

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

  1. Зайдите в подмодуль и подтяните новые коммиты:

    cd path/to/submodule
    git fetch
    git checkout origin/main
    
  2. Вернитесь в родительский репозиторий и зафиксируйте новое состояние:

    cd ../..
    git add path/to/submodule
    git commit -m "Обновить подмодуль до новой версии"
    

Вопрос 5. Как удалить подмодуль полностью, чтобы он исчез и из статуса, и из конфигурации?

Ответ:

Шаги:

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

    git rm -f path/to/submodule
    
  2. Удалите соответствующий блок из файла .gitmodules.
  3. При необходимости удалите настройки подмодуля из .git/config.
  4. Закоммитьте изменения:

    git commit -m "Удалить подмодуль path/to/submodule"
    

После этого git submodule status перестанет показывать удаленный подмодуль.

Стрелочка влевоОбновление подмодулей в Git - git submodule updateИнициализация подмодулей в Git - git submodule initСтрелочка вправо

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

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