tag - Cómo hacer un directorio existente dentro de un repositorio git un submódulo git
git tags best practices (3)
Estoy muy confundido acerca de git-submódulos.
Básicamente, mi problema es que no puedo hacer que git entienda que ~/main-project/submodule
es un submódulo.
Tengo buena experiencia con submódulos de git:
en mi repositorio de archivos de puntos creé el archivo .gitmodules en ~/dotfiles-repo
y agregué allí rutas y urls. Desde entonces, si realizo cambios en los archivos dentro de los submódulos y ejecuto el git status
, obtendría algo como: .vim/bundle/auto-complete (new commits) # in red
.gitmodules
archivo .gitmodules
en ~/main-project
pero:
- Si realizo cambios en
~/main-project/submodule
e incluso presiono los cambios, no obtengo una respuesta similar como<submodule> (new commits) # in red
al ejecutar elgit status
en~/main-project
. Acabo de recibir los cambios que se hicieron en esos directorios. Cuando golpeo los enlaces de las carpetas en
github
para estos directorios, no me dirigen a los repositorios en sí, sino que me mantengo en el mismo repositorio.- Tal vez me esté perdiendo todo el punto. ¿Cuáles son las principales características de los submódulos?
- ¿Por qué git entiende los submódulos en el repositorio de archivos de puntos pero no en mi otro repositorio ?
- ¿Es porque ya le he dicho a git que agregue los archivos dentro de
~/main-project/submodule
al índice?
He leído esta pregunta que me llevó a esta respuesta. Pero no estoy seguro de que necesite git-subtree
. No quiero hacer cosas que puedan hacer cambios difíciles de revertir.
Edición: esta solución de duplicado sugerida tampoco funcionó, recibí un error de que las
Updates were rejected because the remote contains work that you do not have locally
. Parece que @GabLeRoux prácticamente me dijo que empujara<repo-A>
a la url de<repo-B>
.
La solución es bastante simple. Fue extraído de here .
-
git rm submodule-dir
Esto borrará todos los archivos que git estaba siguiendo después ensubmodule-dir
-
rm -rf submoduledir
Esto eliminará todos los demás archivos que podrían haber quedado ensubmodule-dir
porque git los ignoró. - Ahora, tenemos que comprometernos para eliminar los archivos del índice:
git commit
Después de la confirmación, limpiamos los archivos que git siguió y no seguimos ensubmodul-dir
. Ahora es el momento de hacer: -
git submodule add <remote-path-to-submodule>
Esto volverá a agregar el submódulo pero como un submódulo verdadero. - En este punto, puede ser una buena idea revisar
.gitmodules
y ver si los submódulos se han agregado correctamente. En mi caso ya tenía un archivo.gitmodules
, así que tuve que modificarlo.
EDITAR
Desde v2.12.0-rc0 , y después de este compromiso , recibimos git submodule absorbgitdirs
y es exactamente lo que necesitaba en el momento en que publiqué esta pregunta.
Esto es lo que indican los docs este comando:
Si un directorio git de un submódulo está dentro del submódulo, mueva el directorio git del submódulo a su
$GIT_DIR/modules
superproyectos$GIT_DIR/modules
y luego conecte el directorio git y su directorio de trabajo configurandocore.worktree
y agregando un archivo .git apuntando al directorio git incrustado en el directorio git de superproyectos.
Entonces, en lugar de comenzar de nuevo como se sugiere en las respuestas anteriores de @DomQ y yo, uno puede simplemente agregar lo siguiente:
- Sin quitar del índice el submódulo, agregue la url del submódulo a
.gitmodules
y.git/config
con
git submodule add <url> <path>
- Mueva el directorio
$GIT_DIR
del submódulo (.git
en repositorios regulares) a.git/modules/<path>
con
git submodule absorbgitdirs <path>
Para responder a sus preguntas en orden:
- El purpose de los submódulos de acuerdo con GitHub. En cuanto a las características, se ha diseñado para que se conceptualice como un repositorio secundario (que casi puede tratarse como cualquier otro archivo), que es la versión controlada por un repositorio principal, donde el padre rastrea el ID de confirmación actual del submódulo (repositorio secundario) más bien que sea contenido
- Lo más probable es que ya haya agregado los archivos al índice del repositorio. En cuyo caso, la solución es
git rm --cached submodule-name/
. Luego cree un compromiso intermedio, seguido de la adición de la carpeta como un repositorio :git add submodule-name
(observe que no hay una barra diagonal al final de submodule-name en el caso de los submódulos). - Si :)
La answer que mencionó también puede corregir la historia de sus compromisos:
- Ventajas :
Esa carpeta se tratará como un submódulo en todo su historial de confirmaciones, no solo en todas las confirmaciones futuras. Esto evita cualquier complicación si se registra en una versión anterior en la que se trató como una carpeta. Esto es una complicación porque cuando regresa a la punta de su sucursal, es posible que también deba ingresar su submódulo y verificar el último compromiso para restaurar todos los archivos (que pueden eliminarse de su directorio de trabajo). Esto podría evitarse haciendo algún tipo de comprobación recursiva a su último compromiso.
- Desventajas :
Si se modifica el historial de confirmaciones, todos los demás contribuidores también tendrían que volver a clonar el proyecto, ya que obtendrán conflictos de combinación o algo peor; Reintroducir el problema vuelve a comprometerse en el proyecto.
Básicamente, no hay mejor manera que fingir comenzar de nuevo :
- Asegúrate de que todo está comprometido en todas partes
- Mueve tu sub-repositorio fuera del camino
-
git submodule add
desde el control remoto del sub-repositorio -
cd mysubmodule
-
git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
-
git merge FETCH_HEAD
Para explicar por qué esto es así, me parece que se necesita una comprensión más profunda de qué son los submódulos, de lo que se puede obtener de la página de manual de git-submodule(1)
(o incluso el capítulo relevante del libro de Git ). Encontré algunas explicaciones más detalladas en esta publicación de blog , pero como esa publicación es un poco larga, me tomo la libertad de resumirlas aquí.
En un nivel bajo, un submódulo de git consta de los siguientes elementos,
- Un objeto de confirmación en la parte superior del árbol de submódulos,
- (En versiones recientes de Git) Un subdirectorio en
.git/modules
para alojar los objetos Git para el submódulo, - Una entrada en el archivo de configuración
.gitmodules
.
El objeto de confirmación está contenido (o, más precisamente, referenciado por SHA1) en el objeto del árbol padre. Esto es inusual, ya que las cosas suelen suceder al revés, pero esto explica por qué ve aparecer un directorio en el git status
del repositorio principal después de haber realizado una confirmación en el submódulo. También puede realizar algunos experimentos con git ls-tree
para observar este objeto de confirmación con más detalle.
El subdirectorio en .git/modules
representa un subdirectorio .git
en el submódulo; y de hecho, hay un archivo .git
en el submódulo que apunta al primero usando una línea gitdir:
. Este es el comportamiento predeterminado desde la versión 1.7.8 de Git . No estoy seguro de por qué todo no funcionaría si siguiera teniendo un directorio .git
separado, excepto que, como se indica en las notas de la versión, es probable que tenga problemas al cambiar entre una rama que tiene el submódulo y otra que no.
El archivo .gitmodules
proporciona la URL que git submodule update --remote
y amigos deben extraer; lo que obviamente es distinto del conjunto de controles remotos del repositorio principal. Tenga en cuenta también que .gitmodules
se copia en parte en .git/config
mediante el comando git submodule sync
y otros comandos que lo invocan detrás de escena.
Si bien es bastante fácil hacer los cambios necesarios a mano para .gitmodules
+ .git/config
, y también para .git/modules
+ mysubmodule/.git
(y, de hecho, hay incluso git submodule absorbgitdirs
para este último), no es realmente una porcelana para crear solo el objeto de compromiso en el árbol . De ahí la solución propuesta al mover + rehacer los cambios presentados anteriormente.