Manera fácil de extraer el último de todos los submódulos git

1848

Estamos usando submódulos git para administrar un par de proyectos grandes que dependen de muchas otras bibliotecas que hemos desarrollado. Cada biblioteca es un repositorio separado que se incorpora al proyecto dependiente como un submódulo. Durante el desarrollo, a menudo queremos tomar la última versión de cada submódulo dependiente.

¿Git tiene un comando incorporado para hacer esto? Si no, ¿qué tal un archivo por lotes de Windows o similar que pueda hacerlo?

Brad Robinson
fuente
git-deep debería ayudar con esto.
Mathew Kurian
99
@Brad, ¿desea actualizar sus copias de submódulos a las revoluciones de confirmación nombradas en el proyecto maestro; o quieres obtener la última confirmación HEAD de cada submódulo? La mayoría de las respuestas aquí abordan las primeras; Mucha gente quiere lo último.
chrisinmtown

Respuestas:

2467

Si es la primera vez que revisa un repositorio, debe usarlo --initprimero:

git submodule update --init --recursive

Para git 1.8.2 o superior, la opción --remotese agregó para admitir la actualización a los últimos consejos de sucursales remotas:

git submodule update --recursive --remote

Esto tiene el beneficio adicional de respetar cualquier rama "no predeterminada" especificada en los archivos .gitmoduleso .git/config(si tiene alguna, la predeterminada es origen / maestro, en cuyo caso algunas de las otras respuestas aquí también funcionarían).

Para git 1.7.3 o superior, puede usar (pero los siguientes trucos sobre qué actualización todavía se aplica):

git submodule update --recursive

o:

git pull --recurse-submodules

si desea llevar sus submódulos a los últimos commits en lugar del commit actual al que apunta el repositorio.

Ver git-submodule (1) para más detalles.

Henrik Gustafsson
fuente
299
Probablemente deberías usar git submodule update --recursivehoy en día.
Jens Kohl
38
Mejora del rendimiento:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev el
18
La actualización actualizará cada submódulo a la revisión especificada, no la actualizará a la última para ese repositorio.
Peter DeWeese
21
Solo para agregar, pegarse ciegamente origin masteral final de este comando podría tener resultados inesperados si algunos de sus submódulos están rastreando una rama o nombre de ubicación diferente de ese submódulo en particular. Obvio para algunos, pero probablemente no para todos.
Nathan Hornby
31
Solo para aclarar para todos. git submodule update --recursivebusca ver qué revisión ha almacenado el repositorio principal para cada submódulo, luego verifica esa revisión en cada submódulo. No NO tire las últimas confirmaciones para cada submódulo. git submodule foreach git pull origin mastero git pull origin master --recurse-submoduleses lo que desea si tiene la intención de actualizar cada submódulo al último desde sus repositorios de origen. Solo entonces obtendrá cambios pendientes en el repositorio principal con hashes de revisión actualizados para submódulos. Revisa eso y estarás bien.
Chev
637
git pull --recurse-submodules --jobs=10

una característica que git aprendió por primera vez en 1.8.5.

Hasta que se solucione el error , por primera vez debe ejecutar

actualización de submódulo git --init --recursive

Alexander Bartosh
fuente
29
upvoted, uso esto: alias update_submodules = 'git pull --recurse-submodules && git submodule update'
Stephen C
3
Esto funciona si los submódulos ya se han extraído al menos una vez, pero para los submódulos que nunca se han extraído, consulte la respuesta de gahooa a continuación.
Matt Browne
8
Esto llevará a la versión que especifica el repositorio superior; NO tira de la CABEZA. Por ejemplo, si TopRepo especifica una versión 2 detrás de HEAD para SubRepo, esto extraerá SubRepo con esa versión que está 2 atrás. Otras respuestas aquí tiran HEAD en SubRepo.
Chris Moschini
11
Nota que ni git pull --recurse-submodulesni git submodule update --recursiveno , no initialize recién submódulos añadió. Para inicializarlos necesitas ejecutar git submodule update --recursive --init. Cita del manual : si el submódulo aún no se ha inicializado y solo desea utilizar la configuración tal como está almacenada en .gitmodules, puede inicializar automáticamente el submódulo con la opción --init.
patryk.beza
1
quizás agregue una pista a la git submodule update --recursive --remoteque también se actualizan los submódulos a la última revisión remota en lugar del SHA-1 almacenado.
Hanno S.
386

En init ejecutando el siguiente comando:

git submodule update --init --recursive

desde el directorio git repo, funciona mejor para mí.

Esto extraerá todos los últimos submódulos incluidos.

Explicado

git - the base command to perform any git command
    submodule - Inspects, updates and manages submodules.
        update - Update the registered submodules to match what the superproject
        expects by cloning missing submodules and updating the working tree of the
        submodules. The "updating" can be done in several ways depending on command
        line options and the value of submodule.<name>.update configuration variable.
            --init without the explicit init step if you do not intend to customize
            any submodule locations.
            --recursive is specified, this command will recurse into the registered
            submodules, and update any nested submodules within.

Después de esto, solo puede ejecutar:

git submodule update --recursive

desde el directorio git repo, funciona mejor para mí.

Esto extraerá todos los últimos submódulos incluidos.

abc123
fuente
10
Sí, la respuesta más votada fue la mejor manera de hacerlo en el '09, pero ahora es definitivamente más simple e intuitiva.
Michael Scott Cuthbert
2
@MichaelScottCuthbert gracias, estoy seguro de que en otros 3 años este comando también estará loco
abc123
55
Sin embargo, esto no verifica la última revisión del submódulo, solo la última revisión que el padre está rastreando.
Nathan Osman
44
@NathanOsman, que es lo que quieres ... terminarás con un código roto al no seguir el seguimiento de revisión de los padres. Si usted es el mantenedor de los padres, puede actualizarlos usted mismo y confirmarlos.
abc123
2
Sí, pero según tengo entendido, eso no es lo que quería el OP.
Nathan Osman el
305

Nota: Esto es de 2009 y puede haber sido bueno entonces, pero ahora hay mejores opciones.

Usamos esto Se llama git-pup:

#!/bin/bash
# Exists to fully update the git repo that you are sitting in...

git pull && git submodule init && git submodule update && git submodule status

Simplemente colóquelo en un directorio bin adecuado (/ usr / local / bin). Si está en Windows, es posible que deba modificar la sintaxis para que funcione :)

Actualizar:

En respuesta al comentario del autor original acerca de extraer todos los HEAD de todos los submódulos, esa es una buena pregunta.

Estoy bastante seguro de que gitno tiene un comando para esto internamente. Para hacerlo, necesitaría identificar qué es realmente HEAD para un submódulo. Eso podría ser tan simple como decir que masteres la rama más actualizada, etc.

Después de esto, cree un script simple que haga lo siguiente:

  1. busque git submodule statusrepositorios "modificados". El primer carácter de las líneas de salida indica esto. Si se modifica un repositorio secundario, es posible que NO desee continuar.
  2. para cada repositorio listado, cd en su directorio y ejecutar git checkout master && git pull. Verificar errores.
  3. Al final, le sugiero que imprima una pantalla al usuario para indicar el estado actual de los submódulos, ¿tal vez le pida que agregue todo y se comprometa?

Me gustaría mencionar que este estilo no es realmente para lo que se diseñaron los submódulos git. Por lo general, desea decir que "LibraryX" está en la versión "2.32" y permanecerá así hasta que le diga que "actualice".

Eso es, en cierto sentido, lo que está haciendo con el script descrito, pero de manera más automática. Se requiere cuidado!

Actualización 2:

Si está en una plataforma de Windows, es posible que desee ver el uso de Python para implementar el script, ya que es muy capaz en estas áreas. Si estás en Unix / Linux, entonces sugiero solo un script bash.

¿Necesita alguna aclaración? Solo publica un comentario.

gahooa
fuente
No creo que eso sea lo que quiero. No extraerá la versión de los submódulos con los que se comprometió por última vez el superproyecto. Quiero extraer la versión principal de todos los submódulos.
Brad Robinson
3
Esto funciona muy bien y funciona no solo para actualizar los submódulos sino también para buscarlos por primera vez si eso es lo que necesita.
Matt Browne
Solo estoy obteniendo "No hay información de seguimiento para la sucursal actual. Especifique con qué sucursal desea fusionarse". No importa lo que intente: /
Nathan Hornby
99
¿Por qué no crear un alias para ello? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'y luego úsalo git pupsin ningún script.
fracz
Gracias, por alguna razón, aunque tengo git 1.9.1 tuve que realizar git submodule initdespués del primer tirón que tenía submódulos incluidos, para que todo comenzara a funcionar correctamente.
Ben Usman
164

Henrik está en el buen camino. El comando 'foreach' puede ejecutar cualquier script de shell arbitrario. Dos opciones para sacar lo último podrían ser,

git submodule foreach git pull origin master

y,

git submodule foreach /path/to/some/cool/script.sh

Eso iterará a través de todos los submódulos inicializados y ejecutará los comandos dados.

mturquette
fuente
144

Lo siguiente funcionó para mí en Windows.

git submodule init
git submodule update
zachleat
fuente
66
Claramente, esto no es lo que solicitó el OP. Solo se actualizará a la confirmación de submódulo asociada y no a la última.
Patrick
52
Sin embargo, esto es lo único en esta página que consiguió que git extrajera submódulos la primera vez que revisé un repositorio
theheadofabroom
2
También puede usar: actualización de submódulo git --init --recursive (particularmente si el submódulo en cuestión es RestKit de un clon nuevo)
HCdev
33

Editar :

En los comentarios se señaló (por philfreo ) que se requiere la última versión. Si hay submódulos anidados que necesitan estar en su última versión:

git submodule foreach --recursive git pull

----- Comentario desactualizado a continuación -----

¿No es esta la forma oficial de hacerlo?

git submodule update --init

Lo uso todo el tiempo. No hay problemas hasta ahora.

Editar:

Acabo de descubrir que puedes usar:

git submodule foreach --recursive git submodule update --init 

Lo que también extraerá recursivamente todos los submódulos, es decir, dependencias.

antitóxico
fuente
55
Su respuesta no responde a la pregunta del OP, pero para hacer lo que ha propuesto puede simplemente decirgit submodule update --init --recursive
philfreo
2
Ya veo, se necesita la última versión. Bueno, esto podría ser útil si hay submódulos anidados: git submodule foreach --recursive git pull
antitóxico
1
Sin embargo, no pude hacer que ninguno de estos descargara nada; sin embargo, la "actualización de submódulo git --init --recursive" funcionó para mí.
BrainSlugs83
33

Como puede suceder que la rama predeterminada de sus submódulos no sea asímaster , así es como automatizo las actualizaciones completas de submódulos de Git:

git submodule init
git submodule update
git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'
Sebastien Varrette
fuente
de las muchas respuestas a las muchas preguntas, esta funcionó para mí (2019, error de github con identificadores de hash específicos)
philshem
30

Primera vez

Submódulo de clonación e inicio

git clone [email protected]:speedovation/kiwi-resources.git resources
git submodule init

Descanso

Durante el desarrollo, simplemente extraiga y actualice el submódulo

git pull --recurse-submodules  && git submodule update --recursive

Actualice el submódulo Git a la última confirmación de origen

git submodule foreach git pull origin master

La forma preferida debe estar debajo

git submodule update --remote --merge

nota: los dos últimos comandos tienen el mismo comportamiento

Yash
fuente
Hice un clon git sin submódulos por error y todas las demás opciones no funcionaron, nadie clonó submódulos. Usando el tuyo, git submodule updatehizo el truco. Ahora estoy descargando datos de submódulos que faltan en el primer paso del clon. Gracias. No soy bueno en git: C
m3nda
Esta respuesta es realmente una muy buena respuesta para hacer una pregunta aquí arriba: ¿por qué tengo que ".. - submódulos recursivos .." y luego adicionalmente "... actualizar ..." e incluso ".. .foreach ... "más tarde para obtener la última confirmación? ¡Todo esto no se parece a GIT en absoluto! ¿Qué está haciendo "actualizar" y por qué tengo que ir manualmente a cada módulo para extraer? ¿No es eso lo que está haciendo "... --recurse-submodules .."? ¿Alguna pista?
Peter Branforn
20

No sé desde qué versión de git funciona, pero eso es lo que estás buscando:

git submodule update --recursive

También lo uso git pullpara actualizar el repositorio raíz:

git pull && git submodule update --recursive
Jens Kohl
fuente
10

Las respuestas anteriores son buenas, sin embargo, estábamos usando git-hooks para facilitar esto, pero resulta que en git 2.14 , puede establecer git config submodule.recurseen verdadero para permitir que los submódulos se actualicen cuando acceda a su repositorio de git.

Sin embargo, esto tendrá el efecto secundario de impulsar todos los cambios de submódulos que tenga si están en ramas, pero si ya necesita ese comportamiento, esto podría hacer el trabajo.

Se puede hacer usando:

git config submodule.recurse true
JamesD
fuente
Debo amar esta opción, desafortunadamente todavía necesito usarla de git submodule initantemano si tu submódulo aún no está inicializado.
Pellet
5

Git para Windows 2.6.3 :

git submodule update --rebase --remote

Seúl
fuente
Ese es el único que funcionó para mí. Ni siquiera pude iniciar o actualizar ya que el puntero del submódulo apuntaba a una versión que ya no estaba en el control remoto
Pavel P el
4

Desde el nivel superior en el repositorio:

git submodule foreach git checkout develop
git submodule foreach git pull

Esto cambiará todas las ramas para desarrollar y extraer lo último

Srayan Guhathakurta
fuente
2
No funciona para mí, con git 2.7.
Bruno Haible
¿Tiene algo como un archivo Sln de Everything que agrega todas las referencias del proyecto en el árbol? Además, ¿qué error ves? ¿Puedes revisar tu archivo de gitignore también
Srayan Guhathakurta
1
git submodule foreach git pull origin masterTuve que agregar la rama que quería buscar. Aparte de eso, funcionó perfectamente.
Torxed el
3

Hice esto adaptando la respuesta de gahooa anterior :

Integrarlo con un git [alias]...

Si su proyecto principal tiene algo como esto en .gitmodules:

[submodule "opt/submodules/solarized"]
    path = opt/submodules/solarized
    url = [email protected]:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
    path = opt/submodules/intellij-colors-solarized
    url = [email protected]:jkaving/intellij-colors-solarized.git

Agregue algo como esto dentro de su .gitconfig

[alias]
    updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" "

Luego, para actualizar sus submódulos, ejecute:

git updatesubs

Tengo un ejemplo en el repositorio de configuración de mi entorno .

Tom
fuente
3

Todo lo que necesitas hacer ahora es un simple git checkout

Solo asegúrese de habilitarlo a través de esta configuración global: git config --global submodule.recurse true

Bolita
fuente
2

Aquí está la línea de comandos para extraer de todos sus repositorios git, ya sean submódulos o no:

ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
find "$ROOT" -name .git -type d -execdir git pull -v ';'

Si lo ejecuta en su repositorio git superior, puede reemplazarlo "$ROOT"en ..

kenorb
fuente
1

Creo que tendrás que escribir un guión para hacer esto. Para ser honesto, podría instalar Python para hacerlo de manera que se puede utilizar os.walkpara cdque cada directorio y emitir los comandos apropiados. El uso de python o algún otro lenguaje de script, que no sea por lotes, le permitiría agregar / eliminar fácilmente subproyectos sin tener que modificar el script.

baudtack
fuente
1

Observación: no es una manera muy fácil, pero viable y tiene sus propios pros únicos.

Si se desea clonar solo la HEADrevisión de un repositorio y solo HEADs de todos sus submódulos (es decir, para retirar "troncal"), se puede usar el siguiente script de Lua . A veces, un comando simple git submodule update --init --recursive --remote --no-fetch --depth=1puede provocar un giterror irrecuperable . En este caso, uno necesita limpiar el subdirectorio del .git/modulesdirectorio y clonar el submódulo manualmente usando el git clone --separate-git-dircomando. La única complejidad es encontrar la URL , la ruta del .gitdirectorio del submódulo y la ruta del submódulo en el árbol de superproyectos.

Observación: el script solo se prueba con el https://github.com/boostorg/boost.gitrepositorio. Sus peculiaridades: todos los submódulos alojados en el mismo host y .gitmodulescontienen solo URL relativas .

-- mkdir boost ; cd boost ; lua ../git-submodules-clone-HEAD.lua https://github.com/boostorg/boost.git .
local module_url = arg[1] or 'https://github.com/boostorg/boost.git'
local module = arg[2] or module_url:match('.+/([_%d%a]+)%.git')
local branch = arg[3] or 'master'
function execute(command)
    print('# ' .. command)
    return os.execute(command)
end
-- execute('rm -rf ' .. module)
if not execute('git clone --single-branch --branch master --depth=1 ' .. module_url .. ' ' .. module) then
    io.stderr:write('can\'t clone repository from ' .. module_url .. ' to ' .. module .. '\n')
    return 1
end
-- cd $module ; git submodule update --init --recursive --remote --no-fetch --depth=1
execute('mkdir -p ' .. module .. '/.git/modules')
assert(io.input(module .. '/.gitmodules'))
local lines = {}
for line in io.lines() do
    table.insert(lines, line)
end
local submodule
local path
local submodule_url
for _, line in ipairs(lines) do
    local submodule_ = line:match('^%[submodule %"([_%d%a]-)%"%]$')
    if submodule_ then
        submodule = submodule_
        path = nil
        submodule_url = nil
    else
        local path_ = line:match('^%s*path = (.+)$')
        if path_ then
            path = path_
        else
            submodule_url = line:match('^%s*url = (.+)$')
        end
        if submodule and path and submodule_url then
            -- execute('rm -rf ' .. path)
            local git_dir = module .. '/.git/modules/' .. path:match('^.-/(.+)$')
            -- execute('rm -rf ' .. git_dir)
            execute('mkdir -p $(dirname "' .. git_dir .. '")')
            if not execute('git clone --depth=1 --single-branch --branch=' .. branch .. ' --separate-git-dir ' .. git_dir .. ' ' .. module_url .. '/' .. submodule_url .. ' ' .. module .. '/' .. path) then
                io.stderr:write('can\'t clone submodule ' .. submodule .. '\n')
                return 1
            end
            path = nil
            submodule_url = nil
        end
    end
end
Tomilov Anatoliy
fuente