Para el beneficio del lector, esto aquí trata de resumirlo y brindar una guía paso a paso sobre cómo hacerlo si las cosas no funcionan como se esperaba. A continuación se muestra la forma probada y segura para la git
versión 2.17
y superior para deshacerse de un submódulo :
submodule="path/to/sub" # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
- Si esto no funciona para usted, consulte a continuación.
- Sin opciones. Nada peligroso ¡Y ni siquiera consideres hacer más!
- Probado con Debian Buster
2.20.1
y Ubuntu 18.04 2.17.1
.
"$submodule"
es solo para enfatizar dónde poner el nombre, y que hay que tener cuidado con los espacios y similares
- Si está en Windows, ignore la primera línea y reemplácela
"$submodule"
con la forma de Windows de una ruta de acceso especificada correctamente al submódulo. (No soy Windows)
¡Advertencia!
¡Nunca toque el interior del .git
directorio usted mismo! La edición en el interior .git
entra en el lado oscuro. Manténgase alejado a toda costa!
Y sí, puedes culpar git
por esto, ya que muchas cosas útiles faltaban git
en el pasado. Como una forma adecuada de eliminar submódulos nuevamente.
Creo que hay una parte muy peligrosa en la documentación de git submodule
. Recomienda eliminarse $GIT_DIR/modules/<name>/
.
En mi opinión, esto no solo es incorrecto, ¡es extremadamente peligroso y provoca grandes dolores de cabeza en el futuro! Vea abajo.
Tenga en cuenta que
git module deinit
es el inverso directo de
git module init
pero
git submodule deinit -- module
git rm -- module
También es todo lo contrario a
git submodule add -- URL module
git submodule update --init --recursive -- module
porque algunos comandos básicamente necesitan hacer más que una sola cosa:
git submodule deinit -- module
- (1) actualizaciones
.git/config
git rm
- (2) elimina los archivos del módulo
- (3) elimina recursivamente los submódulos del submódulo
- (4) actualizaciones
.gitmodules
git submodule add
- extrae los datos para
.git/modules/NAME/
- (1) sí
git submodule init
, así que actualizaciones.git/config
- (2)
git submodule update
, por lo tanto, extrae el módulo de forma no recursiva
- (4) actualizaciones
.gitmodules
git submodule update --init --recursive -- module
- extrae más datos si es necesario
- (3) comprueba los submódulos del submódulo de forma recursiva
Esto no puede ser completamente simétrico, ya que mantenerlo estrictamente simétrico no tiene mucho sentido. Simplemente no hay necesidad de más de dos comandos. También "extraer los datos" está implícito, porque lo necesita, pero no se elimina la información almacenada en caché, porque esto no es necesario en absoluto y podría borrar datos valiosos.
Esto realmente es desconcertante para los recién llegados, pero básicamente es algo bueno: git
simplemente hace lo obvio y lo hace bien, y ni siquiera trata de hacer más. git
es una herramienta que debe hacer un trabajo confiable, en lugar de ser simplemente otra "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" se traduce para mí como "una versión malvada de una navaja suiza").
Entonces entiendo las quejas de la gente, diciendo "¿Por qué no hace git
lo obvio por mí?". Esto se debe a que "obvio" aquí depende del punto de vista. La fiabilidad en todas y cada una de las situaciones es mucho más importante. Por lo tanto, lo que es obvio para usted a menudo no es lo correcto en todas las situaciones técnicas posibles. Recuerde que: AFAICS git
sigue el camino técnico, no el social. (De ahí el nombre inteligente: git)
Si esto falla
Los comandos anteriores pueden fallar debido a lo siguiente:
- Tu
git
es demasiado viejo. Luego usa uno nuevogit
. (Vea a continuación cómo hacerlo).
- Tiene datos no confirmados y puede perder datos. Entonces mejor comprometerlos primero.
- Su submódulo no está limpio en un
git clean
sentido. Luego, primero limpie su submódulo usando ese comando. (Vea abajo.)
- Has hecho algo en el pasado que no es compatible
git
. Entonces estás en el lado oscuro y las cosas se ponen feas y complicadas. (Quizás usar otra máquina lo arregle).
- Tal vez hay más formas de fallar que no conozco (solo soy un
git
usuario avanzado).
Posibles soluciones siguen.
Usa una nueva git
Si su máquina es demasiado vieja, no hay submodule deinit
en su git
. Si no desea (o no puede) actualizar su git
, ¡simplemente use otra máquina con una más nueva git
! git
está destinado a estar completamente distribuido, por lo que puede usar otro git
para hacer el trabajo:
workhorse:~/path/to/worktree$ git status --porcelain
no debe dar salida a nada! Si es así, ¡primero limpia las cosas!
workhorse:~/path/to/worktree$ ssh account@othermachine
othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
- Ahora haz las cosas del submódulo
othermachine:~/TMPWORK$ git commit . -m . && exit
workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD
. Si esto no funciona, usegit reset --soft FETCH_HEAD
- Ahora limpie las cosas, hasta que
git status
esté limpio nuevamente. Puede hacerlo, porque lo ha tenido limpio antes, gracias al primer paso.
Esto othermachine
puede ser alguna VM, o algún Ubuntu WSL bajo Windows, lo que sea. Incluso un chroot
(pero supongo que usted no es root, porque si lo root
fuera, debería ser más fácil actualizar a la más reciente git
).
Tenga en cuenta que si no puede ssh
entrar, existen muchas formas de transportar git
repositorios. Puede copiar su árbol de trabajo en una memoria USB (incluido el .git
directorio) y clonar desde la memoria. Clone la copia, solo para que las cosas vuelvan a estar limpias. Esto podría ser un PITA, en caso de que sus submódulos no sean accesibles directamente desde otra máquina. Pero también hay una solución para esto:
git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
Puede usar esta multiplicación, y esto se guarda en $HOME/.gitconfig
. Algo como
git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
reescribe URL como
https://github.com/XXX/YYY.git
dentro
/mnt/usb/repo/XXX/YYY.git
Es fácil si comienza a acostumbrarse a git
funciones potentes como esta.
Primero limpiar las cosas
La limpieza manual es buena, porque de esta manera quizás detecte algunas cosas que olvidó.
- Si git se queja de cosas no guardadas, comprométalas y empújelas a un lugar seguro.
- Si git se queja de algunas sobras,
git status
y git clean -ixfd
es tu amigo
- Trate de abstenerse de las opciones
rm
y deinit
siempre que pueda. Las opciones (como -f
) para git
son buenas si eres un profesional. Pero como vino aquí, probablemente no tenga tanta experiencia en el submodule
área. Así que más vale prevenir que curar.
Ejemplo:
$ git status --porcelain
M two
$ git submodule deinit two
error: the following file has local modifications:
two
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
$ cd two
$ git submodule deinit --all
error: the following file has local modifications:
md5chk
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
$ cd md5chk
$ git submodule deinit --all
error: the following file has local modifications:
tino
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
$ cd tino
$ git status --porcelain
?? NEW
$ git clean -i -f -d
Would remove the following item:
NEW
*** Commands ***
1: clean 2: filter by pattern 3: select by numbers 4: ask each
5: quit 6: help
What now> 1
Removing NEW
$ cd ../../..
$ git status --porcelain
$ git submodule deinit two
Cleared directory 'two'
Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'
Ya ves, no hay -f
necesidad de submodule deinit
. Si las cosas están limpias, en cierto git clean
sentido. También tenga en cuenta que git clean -x
no es necesario. Esto significa que git submodule deinit
elimina incondicionalmente los archivos no rastreados que se ignoran. Esto suele ser lo que quieres, pero no lo olvides. A veces, los archivos ignorados pueden ser valiosos, como los datos almacenados en caché que tardan horas o días en calcularse nuevamente.
¿Por qué nunca eliminar $GIT_DIR/modules/<name>/
?
Probablemente las personas quieran eliminar el repositorio en caché, porque tienen miedo de tener un problema más tarde. Esto es cierto, pero encontrarse con ese "problema" es la forma correcta de resolverlo. Debido a que la solución es fácil y si se hace bien, podrá vivir feliz para siempre. Esto evita problemas más engorrosos que cuando elimina los datos usted mismo.
Ejemplo:
mkdir tmptest &&
cd tmptest &&
git init &&
git submodule add https://github.com/hilbix/empty.git two &&
git commit -m . &&
git submodule deinit two &&
git rm two &&
git commit -m . &&
git submodule add https://github.com/hilbix/src.git two
La última línea muestra el siguiente error:
A git directory for 'two' is found locally with remote(s):
origin https://github.com/hilbix/empty.git
If you want to reuse this local git directory instead of cloning again from
https://github.com/hilbix/src.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.
¿Por qué este error? Porque .git/modules/two/
anteriormente se rellenó desde https://github.com/hilbix/empty.git y ahora se volverá a llenar de otra cosa, a saber, https://github.com/hilbix/src.git . No verá esto si lo vuelve a llenar desde https://github.com/hilbix/empty.git
¿Qué hacer ahora? Bueno, ¡haz exactamente lo que te dijeron! Utilizar--name someunusedname
git submodule add --name someunusedname https://github.com/hilbix/src.git two
.gitmodules
entonces parece
[submodule "someunusedname"]
path = two
url = https://github.com/hilbix/src.git
ls -1p .git/modules/
da
someunusedname/
two/
De esta manera, en el futuro, puede cambiar ramas / commit hacia adelante y hacia atrás y nunca volverá a tener problemas , debido a que two/
tiene dos repositorios ascendentes diferentes (y posiblemente incompatibles). Y lo mejor es: también mantiene ambos en caché localmente.
- Esto no solo es cierto para ti. También es cierto para todos los demás que usan su repositorio.
- Y no pierdes historia. En caso de que haya olvidado introducir la última versión del antiguo submódulo, puede ingresar la copia local y hacerlo más adelante. Tenga en cuenta que es bastante común que alguien se olvide de presionar algunos submódulos (porque esto es un PITA para los recién llegados, hasta que se acostumbren
git
).
Sin embargo, si eliminó el directorio almacenado en caché, ambos pagos diferentes se toparán entre sí, porque no utilizará las --name
opciones, ¿verdad? Entonces, cada vez que realice el pago, tal vez tenga que eliminar el .git/modules/<module>/
directorio una y otra vez. Esto es extremadamente engorroso y hace que sea difícil usar algo así git bisect
.
Por lo tanto, hay una razón muy técnica para mantener este directorio de módulos como marcador de posición. Las personas que recomiendan eliminar algo a continuación .git/modules/
no lo saben mejor o se olvidan de decirle que esto hace que las funciones potentes sean git bisect
casi imposibles de usar si cruza esa incompatibilidad de submódulos.
Otra razón se muestra arriba. Mira el ls
. Que ves alli
Bueno, la segunda variante del módulo two/
no está debajo .git/modules/two/
, ¡está debajo .git/modules/someunusedname/
! ¡Así que cosas como git rm $module; rm -f .git/module/$module
están totalmente mal! ¡Debes consultar module/.git
o .gitmodules
encontrar lo correcto para eliminar!
Entonces, no solo la mayoría de las otras respuestas caen en esta peligrosa trampa, incluso las git
extensiones muy populares tenían este error ( ahora está solucionado )! ¡Así que mejor mantenga sus manos en el .git/
directorio si no lo hace exactamente, lo que está haciendo!
Y desde el punto de vista filosófico, ¡borrar la historia siempre está mal!
Excepto por la mecánica cuántica , como de costumbre, pero esto es algo completamente diferente.
Para tu información, probablemente lo hayas adivinado: hilbix es mi cuenta de GitHub.
git rm modulename
yrm -rf .git/modules/modulename