¿Cómo muevo un submódulo Git existente dentro de un repositorio Git?

356

Me gustaría cambiar el nombre del directorio de un submódulo Git en mi superproyecto Git.

Supongamos que tengo la siguiente entrada en mi .gitmodulesarchivo:

[submodule ".emacs.d/vimpulse"]  
path = .emacs.d/vimpulse  
url = git://gitorious.org/vimpulse/vimpulse.git

¿Qué debo escribir para mover el .emacs.d/vimpulsedirectorio .emacs.d/vendor/vimpulsesin eliminarlo primero (explicado aquí y aquí ) y luego volver a agregarlo?

¿Git realmente necesita la ruta completa en la etiqueta del submódulo?

[submodule ".emacs.d/vimpulse"]

¿O también es posible almacenar solo el nombre del subproyecto?

[submodule "vimpulse"]
cardo
fuente
NOTA: el OP responde a su propia pregunta con el git mvcomando, justo en la pregunta.
Dan Rosenstark
SIN EMBARGO, no puedes usarlo git mvasí. Use deinitentonces rm como se especifica stackoverflow.com/a/18892438/8047 .
Dan Rosenstark
14
@Yar: al menos en git 2.0.0, git mv solo funciona para submódulos también, no necesita nada más.
Pedro Romano
99
Comenzando con Git, 1.8.5los submódulos móviles se admiten de forma nativa mediante el git mvcomando ( de las notas de la versión , primero vinculadas por el propio @thisch). También respondido aquí
dennisschagt
git mvmueve el submódulo en el espacio de trabajo y actualiza los archivos .git del submódulo correctamente, pero la subcarpeta dentro de la carpeta .git / modules del repositorio principal permanece igual, ¿está bien? (Estoy usando git 2.19.0 en Windows)
yoyo

Respuestas:

377

Nota: Como se menciona en los comentarios, esta respuesta se refiere a los pasos necesarios con versiones anteriores de git. Git ahora tiene soporte nativo para mover submódulos:

Desde git 1.8.5, git mv old/submod new/submodfunciona como se espera y hace toda la fontanería por usted. Es posible que desee utilizar git 1.9.3 o posterior, ya que incluye correcciones para el movimiento de submódulos.


El proceso es similar a cómo eliminaría un submódulo (consulte ¿Cómo elimino un submódulo? ):

  1. Edite .gitmodulesy cambie la ruta del submódulo adecuadamente, y colóquelo en el índice con git add .gitmodules.
  2. Si es necesario, cree el directorio principal de la nueva ubicación del submódulo ( mkdir -p new/parent).
  3. Mueva todo el contenido del directorio antiguo al nuevo ( mv -vi old/parent/submodule new/parent/submodule).
  4. Asegúrese de que Git rastrea este directorio ( git add new/parent).
  5. Elimine el directorio antiguo con git rm --cached old/parent/submodule.
  6. Mueva el directorio .git/modules/old/parent/submodulecon todo su contenido a .git/modules/new/parent/submodule.
  7. Edite el .git/modules/new/parent/configarchivo, asegúrese de que el elemento de árbol de trabajo apunte a las nuevas ubicaciones, por lo que en este ejemplo debería estarlo worktree = ../../../../../new/parent/module. Por lo general, debe haber dos más ..que directorios en la ruta directa en ese lugar.
  8. Edite el archivo new/parent/module/.git, asegúrese de que la ruta en él apunte a la nueva ubicación correcta dentro de la .gitcarpeta principal del proyecto , así que en este ejemplo gitdir: ../../../.git/modules/new/parent/submodule.

    git status La salida se ve así para mí después:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Finalmente, comete los cambios.

Axel Beckert
fuente
37
Cuando actualice .gitmodules, asegúrese de actualizar esa pathconfiguración y el nombre del submódulo. Por ejemplo, al mover foo / module a bar / module debes cambiar en .gitmodules la sección [submodule "foo/module"]a [submodule "bar/module"], y debajo de esa misma sección path = foo/modulea path = bar/module. Además, debe cambiar en .git / config la sección [submodule "foo/module"]a [submodule "bar/module"].
wilhelmtell
3
Tampoco funcionó para mí ... la solución más cercana que he encontrado es eliminar un submódulo (un problema) y luego volver a agregarlo en la ubicación diferente.
Pablo Olmos de Aguilera C.
33
Una nota muy importante: si fatal: 'git status --porcelain' failed in...solo elimina cualquier archivo .git o directorio en el submódulo.
antitóxico
19
Parece que esta publicación pierde algunos pasos, como editar .git/modules/old/parent/submodule, moverla a la nueva ubicación, actualizar gitdiren old/parent/submodule/.git...
szx
38
Desde git 1.8.5, git mv old/submod new/submodfunciona como se espera y hace toda la fontanería por usted. Probablemente quiera usar git 1.9.3+ porque incluye correcciones para mover submódulos.
Valloric
232

La respuesta más moderna, tomada del comentario anterior de Valloric:

  1. Actualice a Git 1.9.3 (o 2.18 si el submódulo contiene submódulos anidados )
  2. git mv old/submod new/submod
  3. Luego, los .gitmodules y el directorio de submódulos ya están preparados para una confirmación (puede verificar esto con git status).
  4. ¡Compromete los cambios git commity listo!

¡Hecho!

phatmann
fuente
3
De hecho, esto funcionó con la 1.9.3 excepción de un submódulo dentro del submódulo movido. Eso necesitaba un poco de limpieza manual.
Pascal
3
Esto ya debería funcionar en la versión 1.8.5como se describe en las notas de la versión .
dennisschagt
66
Esta respuesta debería obtener 1000 votos a favor, casi hice un lío con mi repositorio siguiendo los pasos descritos anteriormente, realmente StackOverflow debería tener un caso de uso para esta situación.
MGP
55
Wow, esto funcionó de maravilla (git 1.9.5), desearía que fuera la respuesta seleccionada.
Alex Ilyaev
77
Una cosa que esto no hace es que no cambia la etiqueta inicial para el submódulo. Si verifica el .gitmodulesarchivo, old/submodaún se utilizará como etiqueta para el submódulo mientras se haya cambiado la ruta. Para cambiar también la etiqueta, parece que realmente necesita mover la ruta del directorio de módulos dentro .gity luego cambiar manualmente la etiqueta .gitmodules.
CMCDragonkai
55

En mi caso, quería mover un submódulo de un directorio a un subdirectorio, por ejemplo, "AFNetworking" -> "ext / AFNetworking". Estos son los pasos que seguí:

  1. Edite .gitmodules cambiando el nombre y la ruta del submódulo para que sea "ext / AFNetworking"
  2. Mueva el directorio git del submódulo de ".git / modules / AFNetworking" a ".git / modules / ext / AFNetworking"
  3. Mover biblioteca de "AFNetworking" a "ext / AFNetworking"
  4. Edite ".git / modules / ext / AFNetworking / config" y arregle la [core] worktreelínea. La mía cambió de ../../../AFNetworkinga../../../../ext/AFNetworking
  5. Edite "ext / AFNetworking / .git" y corríjalo gitdir. La mía cambió de ../.git/modules/AFNetworkinga../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Finalmente, vi en el estado de git:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

Et voila. El ejemplo anterior no cambia la profundidad del directorio, lo que hace una gran diferencia en la complejidad de la tarea, y no cambia el nombre del submódulo (que puede no ser realmente necesario, pero lo hice para ser coherente con lo que sucedería si agregara un nuevo módulo en esa ruta).

Matt Connolly
fuente
44
Gracias Matt Estaba perdido en la respuesta aceptada. Gracias por cubrir más que el caso base. Esto funcionó a las mil maravillas.
Andrew Hubbs
No necesita barajar las rutas .git / modules ni cambiar el nombre del submódulo (como mencionan Arand y Bob Bell). Sin embargo, hacerlo puede mantener las cosas más limpias.
gatoatigrado
No olvide hacer los pasos 2, 3, 4 y 5 de forma recursiva para cualquier sub-submódulo.
herzbube
22

[Actualización: 26/11/2014] Como Yar resume muy bien a continuación, antes de hacer nada, asegúrese de conocer la URL del submódulo. Si se desconoce, abra .git/.gitmodulesy examine la llave submodule.<name>.url.

Lo que funcionó para mí fue eliminar el submódulo anterior usando git submodule deinit <submodule>seguido de git rm <submodule-folder>. Luego agregue el submódulo nuevamente con el nuevo nombre de carpeta y confirme. Al verificar el estado de git antes de confirmar, se muestra el submódulo antiguo renombrado al nuevo nombre y se modificó .gitmodule.

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"
Mark Mikofski
fuente
1
Esto requiere git 1.8.3 o superior. Vea esta publicación para actualizar su git: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole
1
O, una mejor manera: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole
@MichaelCole ¡Gracias! ¡Estás en lo correcto! Consulte las notas de la versión de Git-1.8.3 . FYI: Ubuntu-13.10 (Saucy Salamander) tiene Git-1.8.3.2 , pero es bueno saber que hay ppa . Además, la estrategia de fusión de subárbol git de la OMI es un mejor enfoque; He abandonado submódulos para mis propios proyectos. Todavía es bueno de entender para los proyectos existentes.
Mark Mikofski
Probé varias soluciones, pero la tuya es la mejor. Solo use la línea de comando para que no necesite (y no deba) modificar ningún archivo git. ¡Gracias!
nahung89
12

El truco parece ser comprender que el .gitdirectorio para submódulos ahora se mantiene en el repositorio maestro, debajo .git/modules, y cada submódulo tiene un .gitarchivo que apunta a él. Este es el procedimiento que necesita ahora:

  • Mueva el submódulo a su nuevo hogar.
  • Edite el .gitarchivo en el directorio de trabajo del submódulo y modifique la ruta que contiene para que apunte al directorio correcto en el directorio del repositorio maestro .git/modules.
  • Ingrese el .git/modulesdirectorio del repositorio principal y busque el directorio correspondiente a su submódulo.
  • Edite el configarchivo, actualizando la worktreeruta para que apunte a la nueva ubicación del directorio de trabajo del submódulo.
  • Edite el .gitmodulesarchivo en la raíz del repositorio principal, actualizando la ruta al directorio de trabajo del submódulo.
  • git add -u
  • git add <parent-of-new-submodule-directory>(Es importante que agregue el padre , y no el directorio del submódulo en sí).

Algunas notas

  • Las [submodule "submodule-name"]líneas .gitmodulesy .git/configdeben coincidir entre sí, pero no corresponden a nada más.
  • El directorio de trabajo del submódulo y el .gitdirectorio deben apuntar correctamente entre sí.
  • Los archivos .gitmodulesy .git/configdeben estar sincronizados.
Paul Gideon Dann
fuente
9

La cadena entre comillas después de "[submódulo" no importa. Puede cambiarlo a "foobar" si lo desea. Se utiliza para encontrar la entrada coincidente en ".git / config".

Por lo tanto, si realiza el cambio antes de ejecutar "git submodule init", funcionará bien. Si realiza el cambio (o recoge el cambio mediante una combinación), deberá editar manualmente .git / config o ejecutar "git submodule init" nuevamente. Si haces lo último, te quedará una entrada inofensiva "varada" con el nombre anterior en .git / config.

Bob Bell
fuente
Esto es realmente molesto, pero tienes razón. La peor parte es que si solo cambia la URL, ejecutar git init no parece actualizarlo, debe editar .git / config manualmente.
crimson_penguin
1
en este caso git submodule syncpropaga el cambio .git/configautomáticamente
CharlesB
9

Simplemente puede agregar un nuevo submódulo y eliminar el antiguo submódulo usando comandos estándar. (debería evitar cualquier error accidental dentro de .git)

Configuración de ejemplo:

mkdir foo; cd foo; git init; 
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

Examine mover 'jquery' a 'proveedor / jquery / jquery':

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`

## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"

## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)

## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

Método de bonificación para submódulos grandes:

Si el submódulo es grande y prefiere no esperar al clon, puede crear el nuevo submódulo utilizando el antiguo como origen y luego cambiar el origen.

Ejemplo (use la misma configuración de ejemplo)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`

# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"

## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"

## remove old submodule
...
Lance Rushing
fuente
Si no está utilizando head, es posible que también deba verificar la versión correcta del módulo en newPath.
Paulmelnikow
2

La solución dada no funcionó para mí, sin embargo, una versión similar sí ...

Esto es con un repositorio clonado, por lo tanto, los repositorios de submódulos git están contenidos en los repositorios superiores .git dir. Todos los cationes son del repositorio superior:

  1. Edite .gitmodules y cambie la configuración "ruta =" para el submódulo en cuestión. (No es necesario cambiar la etiqueta ni agregar este archivo al índice).

  2. Edite .git / modules / name / config y cambie la configuración "worktree =" para el submódulo en cuestión

  3. correr:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

Me pregunto si hace una diferencia si los repositorios son atómicos o submódulos relativos, en mi caso fue relativo (submodule / .git es una referencia al proyecto superior / .git / modules / submodule)

arand
fuente
2

Simplemente use el script de shell git-submodule-move .

Flimm
fuente
Heh, volví a buscar esta pregunta y utilicé una de las respuestas más votadas, y ahora desearía haberme desplazado hacia abajo y ver mi respuesta anterior que había olvidado.
Flimm
2

Acabo de pasar por esta prueba ayer y esta respuesta funcionó perfectamente. Aquí están mis pasos, para mayor claridad:

  1. Asegúrese de que el submódulo esté registrado y enviado a su servidor. También necesita saber en qué rama está.
  2. ¡Necesitas la URL de tu submódulo! Úselo more .gitmodulesporque una vez que elimine el submódulo no estará disponible
  3. Ahora puedes usar deinit, rmy luegosubmodule add

EJEMPLO

Comandos

    git submodule deinit Classes/lib/mustIReally
    git rm foo
    git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus

    # do your normal commit and push
    git commit -a 

NOTA: git mv no hace esto. En absoluto.

Dan Rosenstark
fuente
3
Buen resumen Sin git mvembargo, +1 debería ser mejor en las últimas versiones de Git.
VonC
@VonC Probé en git 1.8.5, bastante seguro de que es tan bueno como parece mv. ¡Gracias!
Dan Rosenstark