Parece que dos escenarios diferentes se mezclan en esta discusión:
escenario 1
Utilizando los punteros de mi repositorio principal para los submódulos, quiero verificar la confirmación en cada submódulo al que apunta el repositorio principal, posiblemente después de iterar primero a través de todos los submódulos y actualizar / extraerlos desde el control remoto.
Esto es, como se señaló, hecho con
git submodule foreach git pull origin BRANCH
git submodule update
Escenario 2, que creo que es a lo que apunta OP
Han ocurrido cosas nuevas en uno o más submódulos, y quiero 1) extraer estos cambios y 2) actualizar el repositorio principal para que apunte a la confirmación HEAD (más reciente) de este / estos submódulos.
Esto sería hecho por
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
No es muy práctico, ya que tendría que codificar n rutas a todos los n submódulos en, por ejemplo, un script para actualizar los punteros de confirmación del repositorio principal.
Sería genial tener una iteración automatizada a través de cada submódulo, actualizando el puntero del repositorio principal (usando git add
) para apuntar a la cabeza del submódulo (s).
Para esto, hice este pequeño script 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
Para ejecutarlo, ejecuta
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Elaboración
En primer lugar, supongo que la rama con el nombre $ BRANCH (segundo argumento) existe en todos los repositorios. Siéntase libre de hacer esto aún más complejo.
El primer par de secciones son algunas comprobaciones de que los argumentos están ahí. Luego saco las últimas cosas del repositorio principal (prefiero usar --ff (avance rápido) cada vez que solo hago pulls. Tengo rebase, BTW).
git checkout $BRANCH && git pull --ff origin $BRANCH
Entonces, puede ser necesario inicializar algunos submódulos, si se han agregado nuevos submódulos o aún no se han inicializado:
git submodule sync
git submodule init
git submodule update
Luego actualizo / extraigo todos los submódulos:
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
Observe algunas cosas: en primer lugar, estoy encadenando algunos comandos de Git usando &&
, lo que significa que el comando anterior debe ejecutarse sin error.
Después de una posible extracción exitosa (si se encontraron cosas nuevas en el control remoto), hago un esfuerzo para asegurarme de que un posible compromiso de fusión no se quede atrás en el cliente. Nuevamente, solo sucede si un tirón realmente trajo cosas nuevas.
Finalmente, la final || true
es asegurar que el script continúe con los errores. Para que esto funcione, todo en la iteración debe estar entre comillas dobles y los comandos Git están entre paréntesis (precedencia del operador).
Mi parte favorita:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
Itere todos los submódulos, con --quiet
, lo que elimina la salida 'Entrar en MODULE_PATH'. Usando 'echo $path'
(debe estar entre comillas simples), la ruta al submódulo se escribe en la salida.
Esta lista de rutas relativas de submódulos se captura en una matriz ( $(...)
): finalmente repita esto y git add $i
actualice el repositorio principal.
Finalmente, una confirmación con algún mensaje que explica que se actualizó el repositorio principal. Este commit será ignorado por defecto, si no se hizo nada. Empuje esto al origen, y ya está.
Tengo un script que ejecuta esto en un trabajo de Jenkins que luego se encadena a una implementación automática programada, y funciona de maravilla.
Espero que esto sea de ayuda para alguien.
--remote
opción, ¿tal vez sería útil marcar eso como la respuesta aceptada en lugar del enfoque "a mano" en la respuesta de Jason?