Git Submodule: как добавить в репозиторий часть другого проекта
Git submodules позволяют подключить к проекту код из внешних репозиториев. Это удобно для повторного использования общих компонентов. Но есть и подводные камни. Давайте разберемся!
Что такое git submodule и когда его использовать
Git submodule - это ссылка из репозитория на определенный коммит во внешнем репозитории. В отличие от простого копирования кода, submodule:
- Сохраняет историю изменений внешнего репозитория
- Позволяет отслеживать обновления и блокировать версию
- Упрощает повторное использование кода в разных проектах
Основные сценарии применения submodules:
- Блокировка версии внешней библиотеки от случайного обновления
- Интеграция работ сторонних разработчиков
- Управление общими для всех проектов компонентами
Однако есть и ограничения: изменения в submodule нужно публиковать отдельно от основного проекта. Работать с сабмодулями должна вся команда.
Как добавить git submodule в проект
Добавим в репозиторий модуль для доступа к хранилищу секретов Hashicorp Vault. Для этого выполним команду:
git submodule add https://github.com/hashicorp/vault-plugin-secrets-kv.git
Git загрузит содержимое указанного репозитория в дочерний каталог vault-plugin-secrets-kv и добавит запись в файл .gitmodules:
path | vault-plugin-secrets-kv |
url | https://github.com/hashicorp/vault-plugin-secrets-kv.git |
Теперь в любой момент можно получить точную версию этого плагина для работы с Vault.
При клонировании репозитория сабмодули не загружаются автоматически. Необходимо явно вызвать команды git submodule init и git submodule update.
Решение проблем, которые могут возникнуть при использовании git submodules
Работа с сабмодулями на первый взгляд проста. Но на практике часто возникают неприятные сюрпризы:
- Потеря коммитов в сабмодуле при его удалении
- Сломанные ссылки на внешние репозитории
- Конфликты при слиянии изменений
Рассмотрим типичный случай: разработчик удалил директорию сабмодуля. Ведь в .gitignore прописана строчка vault-plugin-secrets-kv/. Казалось бы можно переинициализировать подмодуль?
К сожалению, это приведет к потере всех локальных изменений. Потому что Git хранит историю каждого сабмодуля только в его директории. Удалив ее, мы безвозвратно потеряем все коммиты.
Что делать? Восстановить директорию из кеша git или бекапа. Убрать vault-plugin-secrets-kv/ из .gitignore раз и навсегда. И никогда не удалять директории сабмодулей!
Решение проблем, которые могут возникнуть при использовании git submodules
Другая распространенная ситуация - конфликты при обновлении сабмодуля. Например, если мы внесли локальные изменения, а на удаленном репозитории произошли обновления.
Чтобы избежать конфликтов, нужно:
- Закоммитить изменения в сабмодуле
- Выполнить в нем pull или rebase относительно удаленного репозитория
- Обновить ссылку на сабмодуль в родительском репо
Устранение сломанных ссылок на подмодули
Случается, что после клонирования репозитория ссылки на подмодули работают некорректно. Или отображается ошибка "unpopulated submodule directory".
В таком случае нужно убедиться, что в настройках подмодуля прописаны корректные пути. Если с адресацией все в порядке, то выполнить команды:
git submodule sync
git submodule update --init
Ускорение работы с большим количеством подмодулей
Если в проекте много подмодулей (десятки и сотни), то обычные команды начнут работать очень медленно.
В таком случае有两个 варианта оптимизации:
- Инициализировать изменения только в нужных подмодулях
- Использовать псевдокоманды для групповых операций
Риски при удалении подмодулей
Как мы выяснили ранее, удаление директории подмодуля чревато потерей данных. Но что, если удалить только запись из .gitmodules?
Это безопасная операция, но есть подводные камни. Разработчики могут запутаться, внося изменения в числящийся удаленным каталог. Поэтому лучше удалять подмодули корректно с сохранением истории.
Использование git submodule update --remote
Эта команда позволяет указать конкретную ветку или тег в удаленном репозитории для подмодуля. Удобно для отката на стабильную версию.
Например, чтобы переключить подмодуль на тег v1.0.0, достаточно выполнить:
git submodule update --remote -- v1.0.0
В результате HEAD подмодуля изменится на указанный тег.