Кажется, что в этом обсуждении смешиваются два разных сценария:
Сценарий 1
Используя указатели моего родительского репозитория на подмодули, я хочу проверить фиксацию в каждом подмодуле, на который указывает родительский репозиторий, возможно, после первой итерации всех подмодулей и обновления / извлечения их из удаленного модуля.
Это, как указано, сделано с
git submodule foreach git pull origin BRANCH
git submodule update
Сценарий 2, к которому, как мне кажется, ОП стремится
Новые вещи произошли в одном или нескольких подмодулях, и я хочу 1) вытащить эти изменения и 2) обновить родительский репозиторий, чтобы он указывал на HEAD (последний) коммит этого / этих подмодулей.
Это будет сделано
git submodule foreach git pull origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git push origin BRANCH
Не очень практично, поскольку вам придется жестко задавать n путей ко всем n подмодулям, например, скрипт для обновления указателей коммитов родительского репозитория.
Было бы здорово иметь автоматическую итерацию для каждого подмодуля, обновляя указатель родительского репозитория (используя git add
), чтобы он указывал на заголовок подмодуля (ов).
Для этого я сделал небольшой скрипт Bash:
git-update-submodules.sh
#!/bin/bash
APP_PATH=$1
shift
if [ -z $APP_PATH ]; then
echo "Missing 1st argument: should be path to folder of a git repo";
exit 1;
fi
BRANCH=$1
shift
if [ -z $BRANCH ]; then
echo "Missing 2nd argument (branch name)";
exit 1;
fi
echo "Working in: $APP_PATH"
cd $APP_PATH
git checkout $BRANCH && git pull --ff origin $BRANCH
git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git push origin $BRANCH
Чтобы запустить его, выполните
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Разработка
Прежде всего, я предполагаю, что ветка с именем $ BRANCH (второй аргумент) существует во всех репозиториях. Не стесняйтесь делать это еще сложнее.
Первая пара разделов посвящена проверке наличия аргументов. Затем я извлекаю последние материалы родительского репозитория (я предпочитаю использовать --ff (быстрая перемотка вперед) всякий раз, когда я просто выполняю вытягивание. У меня отключен ребаз, кстати).
git checkout $BRANCH && git pull --ff origin $BRANCH
Тогда может потребоваться некоторая инициализация субмодуля, если новые субмодули были добавлены или еще не инициализированы:
git submodule sync
git submodule init
git submodule update
Затем я обновляю / вытягиваю все подмодули:
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
Обратите внимание на несколько вещей: во-первых, я объединяю некоторые команды Git с помощью &&
- то есть предыдущая команда должна выполняться без ошибок.
После возможного успешного извлечения (если новый материал был обнаружен на пульте), я делаю пуш, чтобы убедиться, что возможный коммит-слияние не остался на клиенте. Опять же, это случается только , если действительно приносит новые вещи.
Наконец, последний || true
гарантирует, что скрипт продолжит работу при ошибках. Чтобы это работало, все в итерации должно быть заключено в двойные кавычки, а команды Git заключены в скобки (приоритет оператора).
Моя любимая часть:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
Перебрать все подмодули - с помощью --quiet
, который удаляет вывод «Вход в MODULE_PATH». Используя 'echo $path'
(должно быть в одинарных кавычках), путь к подмодулю записывается в вывод.
Этот список относительных путей подмодулей содержится в массиве ($(...)
) - наконец, выполните итерацию и выполните git add $i
, чтобы обновить родительский репозиторий.
Наконец, коммит с некоторым сообщением, объясняющим, что родительский репозиторий был обновлен. Этот коммит будет проигнорирован по умолчанию, если ничего не было сделано. Переместите это в начало координат, и все готово.
У меня есть сценарий, выполняющий его в задании Jenkins , который впоследствии связывается с запланированным автоматическим развертыванием, и он работает как чудо.
Надеюсь, это кому-нибудь поможет.