oneline - git tag
Actualizar el submódulo de Git al último commit en origen (9)
Tengo un proyecto con un submódulo Git. Es de una URL ssh: // ... y está en confirmación A. La confirmación B ha sido enviada a esa URL, y quiero que el submódulo recupere la confirmación y cambie a ella.
Ahora, mi entendimiento es que la git submodule update
debería hacer esto, pero no lo hace. No hace nada (sin salida, código de salida exitosa). Aquí hay un ejemplo:
$ mkdir foo
$ cd foo
$ git init .
Initialized empty Git repository in /.../foo/.git/
$ git submodule add ssh://user@host/git/mod mod
Cloning into mod...
user@host''s password: hunter2
remote: Counting objects: 131, done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 131 (delta 54), reused 0 (delta 0)
Receiving objects: 100% (131/131), 16.16 KiB, done.
Resolving deltas: 100% (54/54), done.
$ git commit -m "Hello world."
[master (root-commit) 565b235] Hello world.
2 files changed, 4 insertions(+), 0 deletions(-)
create mode 100644 .gitmodules
create mode 160000 mod
# At this point, ssh://user@host/git/mod changes; submodule needs to change too.
$ git submodule init
Submodule ''mod'' (ssh://user@host/git/mod) registered for path ''mod''
$ git submodule update
$ git submodule sync
Synchronizing submodule url for ''mod''
$ git submodule update
$ man git-submodule
$ git submodule update --rebase
$ git submodule update
$ echo $?
0
$ git status
# On branch master
nothing to commit (working directory clean)
$ git submodule update mod
$ ...
También he intentado git fetch mod
, que parece hacer un fetch (¡pero no puedo, porque no solicita una contraseña!), Pero git log
y git show
niegan la existencia de nuevas confirmaciones. Hasta el momento, acabo de estar reiniciando el módulo y volviéndolo a agregar, pero en principio esto es incorrecto y tedioso en la práctica.
@Jason es correcto de una manera pero no del todo.
actualizar
Actualice los submódulos registrados, es decir, clone los submódulos que faltan y verifique la confirmación especificada en el índice del repositorio que lo contiene. Esto hará que los submódulos HEAD se separen a menos que se especifique --rebase o --merge o que el submódulo clave. $ Name.update esté establecido en rebase o fusionar.
Por lo tanto, git submodule update realiza el checkout, pero lo que pasa es que está comprometido en el índice del repositorio que lo contiene. Todavía no sabe nada del nuevo compromiso en sentido ascendente. Así que vaya a su submódulo, obtenga la confirmación que desea y confirme el estado de submódulo actualizado en el repositorio principal y luego haga la git submodule update
Aquí hay una impresionante de una sola línea para actualizar todo lo último en master:
git submodule foreach ''git fetch origin --tags; git checkout master; git pull'' && git pull && git submodule update --init --recursive
El comando git submodule update
realidad le dice a Git que desea que sus submódulos comprueben el compromiso ya especificado en el índice del superproyecto. Si desea actualizar sus submódulos al último compromiso disponible desde su control remoto, deberá hacerlo directamente en los submódulos.
Así que en resumen:
# get the submodule initially
git submodule add ssh://bla submodule_dir
git submodule init
# time passes, submodule upstream is updated
# and you now want to update
# change to the submodule directory
cd submodule_dir
# checkout desired branch
git checkout master
# update
git pull
# get back to your project root
cd ..
# now the submodules are in the state you want, so
git commit -am "Pulled down update to submodule_dir"
O, si eres una persona ocupada:
git submodule foreach git pull origin master
En mi caso, quería que git
actualizara a la última versión y, al mismo tiempo, rellene los archivos faltantes.
Lo siguiente restauró los archivos faltantes (gracias a --force
que no parece haber sido mencionado aquí), pero no hizo ningún nuevo comentario:
git submodule update --init --recursive --force
Esto hizo
git submodule update --recursive --remote --merge --force
Git 1.8.2 presenta una nueva opción: --remote
que permitirá exactamente este comportamiento. Corriendo
git submodule update --remote --merge
buscará los últimos cambios desde el nivel superior en cada submódulo, los combinará y verificará la última revisión del submódulo. Como dicen los documentos :
--remoto
Esta opción solo es válida para el comando de actualización. En lugar de utilizar el SHA-1 grabado del superproyecto para actualizar el submódulo, use el estado de la rama de seguimiento remoto del submódulo.
Esto es equivalente a ejecutar git pull
en cada submódulo, que generalmente es exactamente lo que quieres.
Parece que en esta discusión se mezclan 2 escenarios diferentes:
escenario 1
Usando los punteros de mi repo principal para los submódulos, quiero verificar la confirmación en cada submódulo, a la que apunta el repositorio principal, posiblemente después de la primera iteración de todos los submódulos y la actualización / extracción de estos 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 1 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 estos / submódulos.
Esto se haría 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 repo principal.
Lo que sería genial sería 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 bash-script:
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, ejecute
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Elaboración
En primer lugar, asumo que la rama con el nombre $ BRANCH (segundo argumento) existe en todos los repo. Siéntase libre de hacer esto aún más complejo.
Las primeras secciones de la pareja son algunas comprobaciones de que los argumentos están ahí. Luego saco las últimas cosas del repo de los padres (prefiero usar --ff (avance rápido) siempre que estoy haciendo pulls. Tengo rebase off, por cierto).
git checkout $BRANCH && git pull --ff origin $BRANCH
Entonces podría ser necesaria alguna inicialización de submódulos, si se agregaron nuevos submódulos o no se han iniciado aún:
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 git usando &&
, lo que significa que el comando anterior debe ejecutarse sin error.
Después de un posible tirón exitoso (si se encontraron nuevas cosas en el control remoto), hago un empuje para asegurar que no se quede un posible compromiso de fusión en el cliente. Una vez más, solo sucede si un tirón en realidad trajo nuevas cosas.
Finalmente, la final || true
|| true
es asegurar que el script continúe en los errores. Para hacer que esto funcione, todo en la iteración debe estar envuelto en comillas dobles y los comandos git están envueltos en 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
Iterar todos los submódulos - con --quiet
, lo que elimina la salida ''Ingresando MODULE_PATH''. Usando ''echo $path''
(debe estar entre comillas simples), la ruta al submódulo se escribe en la salida.
Esta lista de rutas de submódulo relativas se captura en una matriz ( $(...)
) - finalmente itere esto y git add $i
para actualizar el repositorio principal.
Finalmente, una confirmación con algún mensaje que explica que el repositorio principal se actualizó. Esta confirmación será ignorada por defecto, si no se hizo nada. Empuje esto a su origen, y ya está.
Tengo un script ejecutando esto en un trabajo de Jenkins, que se encadena a un despliegue automatizado programado después, y funciona como un encanto.
Espero que esto sea de ayuda para alguien.
Sencillo y sencillo, para buscar los submódulos:
git submodule update --init --recursive
y ahora continúe actualizándolos a la última rama maestra (por ejemplo):
git submodule foreach git pull origin master
Su proyecto principal apunta a un compromiso particular en el que debería estar el submódulo. Lo que hace la git submodule update
es tratar de desproteger ese compromiso en cada submódulo que se ha inicializado. El submódulo es realmente un repositorio independiente: simplemente creando un nuevo compromiso en el submódulo y presionando eso no es suficiente, también debe agregar explícitamente la nueva versión del submódulo en el proyecto principal.
Entonces, en su caso, debe encontrar el compromiso correcto en el submódulo. Supongamos que es la punta del maestro:
cd mod
git checkout master
git pull origin master
Ahora vuelve al proyecto principal, prepara el submódulo y confirma que:
cd ..
git add mod
git commit -m "Updating the submodule ''mod'' to the latest version"
Ahora empuje su nueva versión del proyecto principal:
git push origin master
A partir de este momento, si alguien más actualiza su proyecto principal, entonces git submodule update
para ellos actualizará el submódulo, asumiendo que se haya inicializado.
en su proyecto, ejecute el directorio padre:
git submodule update --init
o si tienes submódulos recursivos ejecuta:
git submodule update --init --recursive
a veces esto todavía no funciona porque de alguna manera usted tiene cambios locales en el directorio de submódulos locales mientras se actualiza el submódulo.
La mayoría de las veces, el cambio local puede no ser el que desea confirmar. Puede suceder debido a la eliminación de un archivo en su submódulo, etc. Si es así, reinicie su directorio de submódulo local y vuelva a ejecutar el directorio principal del proyecto:
git submodule update --init --recursive