Как обновить Git submodule до последнего коммита на origin, когда git submodule update не работает? У меня есть submodule с ssh:// URL, который нужно обновить от коммита A до более нового коммита B. Когда я запускаю git submodule update, он не получает новые коммиты, хотя я пробовал различные опции вроде --rebase и синхронизации. Как правильно обновить Git submodule до последнего коммита, когда стандартная команда обновления не работает?
Когда git submodule update не получает последние коммиты из вашего SSH URL подмодуля, вам необходимо вручную получить изменения в директории подмодуля, а затем обновить ссылку в основном репозитории. Стандартная команда обновления только извлекает коммит, уже зафиксированный в родительском репозитории, и не автоматически получает новые коммиты с удаленного сервера.
Содержание
- Понимание, почему обновление подмодуля не работает
- Проблемы, специфичные для SSH URL
- Ручные методы обновления
- Решения по управлению URL
- Подходы к автоматизации
Понимание, почему обновление подмодуля не работает
Команда git submodule update имеет встроенные ограничения, которые вызывают невозможность автоматического получения последних коммитов. Согласно документации Git, команда обновления “по умолчанию не получает новые объекты с удаленного сайта” и только “извлекает коммит, зафиксированный в суперпроекте, в режиме отсоединенного HEAD в подмодуле.”
Это означает:
git submodule updateтолько извлекает коммит, уже ссылкающийся в вашем основном репозитории- Она не получает новые коммиты с удаленного origin
- Она не обновляет ссылку подмодуля для указания на более новые коммиты
- Вам нужно получать изменения отдельно перед обновлением
Как объясняется в одном из ответов на Stack Overflow: “Она НЕ получает последние коммиты для каждого подмодуля. git submodule foreach git pull origin master - это то, что вам нужно, если вы хотите обновить каждый подмодуль до последней версии из их репозиториев origin.”
Проблемы, специфичные для SSH URL
SSH URL в подмодулях могут представлять уникальные проблемы. Исследования показывают несколько распространенных SSH-связанных проблем:
Проблемы с доступом по SSH
Некоторые пользователи сообщают, что они могут клонировать репозитории напрямую через SSH без проблем, но подмодули с SSH URL не работают. Один из пользователей отметил: “Я хочу подчеркнуть, что у меня точно есть доступ к репозиторию, и я могу клонировать репозиторий через ssh без каких-либо проблем. Это происходит ТОЛЬКО когда репозиторий включен в проект как подмодуль.”
Проблемы с форматом SSH URL
SSH URL в файлах .gitmodules иногда опускают префикс ssh://, что может вызывать проблемы с парсингом. Согласно GitHub issue #12295: “Git SSH подмодули, опускающие ‘ssh://’, больше не работают” и “Любой парсинг URL Git подмодуля должен позволять опускать протокол.”
Требования к конфигурации SSH
SSH-основанные URL в .gitmodules работают лучше, когда они не включают имя пользователя, позволяя каждому пользователю настраивать свое имя пользователя сервера в .ssh/config, если оно отличается от локального имени пользователя.
Ручные методы обновления
Когда стандартные команды обновления не работают, вам необходимо вручную обновить подмодуль. Вот наиболее эффективные подходы:
Метод 1: Прямое обновление подмодуля
Для обновления конкретного подмодуля от коммита A к коммиту B:
# Перейдите в директорию подмодуля
cd path/to/submodule
# Получите все изменения с origin
git fetch origin
# Перейдите к конкретному коммиту или ветке, которую вы хотите
git checkout main # или конкретный хэш коммита
git pull origin main
# Вернитесь в основной репозиторий
cd ..
# Обновите родительский репозиторий для ссылки на новый коммит
git add path/to/submodule
git commit -m "Обновить подмодуль до последнего коммита"
Метод 2: Обновление всех подмодулей
Чтобы обновить все подмодули до их последних коммитов:
git submodule foreach 'git fetch origin --tags; git checkout main; git pull origin main'
Метод 3: Рекурсивное обновление с получением данных
Для вложенных подмодулей или комплексного обновления:
git submodule foreach 'git fetch origin --tags'
git submodule foreach 'git checkout main'
git submodule update --init --recursive
Как объясняется в руководстве GeeksforGeeks: “Получите последние изменения и обновите подмодуль. Вернитесь в корневую директорию основного репозитория. Обновите основной репозиторий для указания на новый коммит в подмодуле.”
Решения по управлению URL
Переключение между SSH и HTTPS
Если SSH URL вызывают проблемы, вы можете переключиться на HTTPS в файлах .gitmodules и .git/config:
# Измените URL в .gitmodules
git config -f .gitmodules submodule.your-submodule.url https://github.com/user/repo.git
# Синхронизируйте изменения
git submodule sync
# Обновите подмодуль
git submodule update --init --recursive
Использование относительных URL
Согласно Damir’s Corner: “Я бы рекомендовал использовать относительные URL подмодулей, когда это возможно. Они не заставляют всех разработчиков использовать HTTPS или SSH, оставляя им свободу выбора.”
Программная установка URL
Вы можете устанавливать URL напрямую:
git submodule set-url submodule-name ssh://user@server/path/to/repo
Подходы к автоматизации
Однострочник для преобразования в HTTPS
Для сред CI/CD, где SSH аутентификация проблематична, вы можете преобразовать HTTPS URL в SSH:
# Замените HTTPS на SSH в .gitmodules
sed -i 's|https://|git@|g; s|/|:|g; s|\.git$||g' .gitmodules
# Синхронизируйте и обновите
git submodule sync
git submodule update --init --recursive
Комплексный скрипт обновления
Для регулярного обслуживания подмодулей:
#!/bin/bash
# Получите последние изменения для всех подмодулей
git submodule foreach 'git fetch origin --tags'
# Обновите каждый подмодуль до последнего коммита
git submodule foreach 'git checkout main && git pull origin main'
# Обновите ссылки родительского репозитория
git submodule update --init --recursive
git add .
git commit -m "Обновить все подмодули до последних коммитов"
Источники
- Update Git submodule to latest commit on origin - Stack Overflow
- Changing URLs of Git submodules - Damir’s Corner
- Git submodule documentation
- How to update Git submodule to latest commit on origin - GeeksforGeeks
- Git submodules and SSH access - Stack Overflow
- One-liner to replace HTTPS into SSH url in .gitmodules
- Use HTTPS instead of SSH when cloning git submodules
Заключение
Когда git submodule update не удается получить последние коммиты из вашего SSH URL подмодуля, запомните эти ключевые решения:
- Требуется ручное вмешательство - Стандартная команда обновления только извлекает уже зафиксированные коммиты, она не получает новые
- Используйте
git fetchв директории подмодуля - Всегда получайте последние изменения перед попыткой обновления - Переключайте протоколы при необходимости - Преобразуйте между SSH и HTTPS URL с помощью
git configиgit submodule sync - Обновляйте ссылки родительского репозитория - После изменения подмодуля выполните
git addиgit commitв основном репозитории - Рассмотрите возможность автоматизации скриптов - Для регулярного обслуживания создавайте скрипты, которые получают, извлекают и обновляют все подмодули систематически
Наиболее надежный подход для обновления от коммита A к коммиту B - вручную войти в подмодуль, получить все изменения, перейти к нужному коммиту или ветке, а затем обновить ссылку родительского репозитория. Это обеспечивает полный контроль над тем, на какой коммит указывает подмодуль, и позволяет избежать ограничений автоматических команд обновления.