Git Subtree
Como se mencionó en nuestra página anterior, Git Submodule es útil para casos específicos. Para el seguimiento de dependencias de software, muchos desarrolladores prefieren Git Subtree.
Qué es Git Subtree
Git Subtree es una alternativa a Git Submodule. Permite anidar un repositorio dentro de otro como subdirectorio. Es una de las formas de seguir el historial de las dependencias de software. Pero los subtrees no deben confundirse con los submodules. A diferencia de los submodules, los subtrees no necesitan archivos .gitmodules ni gitlinks en el repositorio. Un subtree es simplemente un subdirectorio al que puedes hacer commit, crear ramas y fusionar junto con tu proyecto.
Por qué usar Git Subtree
Ventajas
- Compatible con Git 1.7.10 y versiones posteriores.
- Gestión de flujo de trabajo sencilla.
- Código del subproyecto disponible después de que el superproyecto esté terminado.
- No se requiere nuevo conocimiento de Git para usar
git subtree. - No añade nuevos archivos de metadatos (por ejemplo,
.gitmodules). - Permite modificar el contenido sin una copia separada del repositorio de la dependencia.
Desventajas
- Requiere aprender una nueva estrategia de merge.
- Proceso complicado para devolver código upstream a los subproyectos.
- El código del superproyecto y del subproyecto se mezcla en el mismo repositorio.
Cómo usar Git Subtrees
Supongamos que hay un proyecto externo y quieres añadirlo a tu repositorio.
Por ejemplo, para añadir una extensión de vim en un repositorio que almacena tu configuración de vim, haz lo siguiente:
git subtree add --prefix .vim/bundle/example https://github.com/Example/vim-example.git master --squashEsto compactará todo el historial del proyecto vim-example dentro de tu carpeta .vim/bundle/example, registrando el SHA-1 de master en ese momento para futuras referencias. La salida es la siguiente, con dos commits:
commit 6d7054b3acea64e2e31f4d6fb2e3be12e5865e87
Merge: 87fa91e ef86deb
Author: Ann Smith<[email protected]m>
Date: Tue Jun 10 13:37:03 2016 +0200
Merge commit 'fe67ddf158faccff4082d78a25c45d8cd93e8ba8' as '.vim/bundle/example'
commit fe67ddf158faccff4082d78a25c45d8cd93e8ba8
Author: Ann Smith<[email protected]m>
Date: Tue May 12 13:37:03 2015 +0200
Squashed '.vim/bundle/example/' content from commit b999b09
git-subtree-dir: .vim/bundle/example
git-subtree-split: b999b09cd9d69f359fa5668e81b09dcfde455ccaPara actualizar la subcarpeta a la última versión del repositorio hijo, ejecuta lo siguiente:
git subtree pull --prefix .vim/bundle/example https://github.com/Example/vim-example.git master --squashPero git subtree almacena los IDs de commit del subproyecto y no referencias en los metadatos. Encuentra el nombre simbólico asociado con un commit:
git ls-remote https://github.com/Example/vim-example.git | grep <commit-sha>Reemplaza <commit-sha> con el hash real del commit.
Rebase después de Git Subtree
Para hacer rebase de un repositorio que contiene subtrees, usa el modo --interactive de git rebase. Puedes eliminar o compactar los commits de merge del subtree y luego ejecutar git rebase --continue. Ten en cuenta que reescribir el historial requiere volver a ejecutar después git subtree add o git subtree pull. Ten presente que reescribir el historial puede causar conflictos de merge al hacer rebase de subtrees, ya que la estructura de commits cambia.
OPCIONES
| -q, --quiet | Suprime mensajes de resultado innecesarios en stderr. |
|---|---|
| -d, --debug | Produce mensajes de depuración adicionales en stderr. |
-P <prefix>, --prefix=<prefix> | Define la ruta en el repositorio hacia el subtree que quieres manipular. Es obligatoria para todos los comandos. |
-m <message>, --message=<message> | Especifica <message> como mensaje de commit para el commit de merge. Solo es válida para add, merge y pull. |
Usar Git Subtree sin seguimiento remoto
Añade el git subtree en una carpeta de prefijo especificada. Usa la opción --squash para conservar todo el historial del subproyecto en tu repositorio principal:
git subtree add --prefix .vim/bundle/vim-double-upon https://hostname.org/example/vim-plugins.git master --squashEl comando realiza un fetch y compacta el historial. La salida normalmente muestra el progreso del fetch seguido de la confirmación de la adición:
git fetch https://hostname.org/example/vim-plugins.git master
warning: no common commits
remote: Counting objects: 325, done.
remote: Compressing objects: 100% (145/145), done.
remote: Total 325 (delta 101), reused 313 (delta 89)
Receiving objects: 100% (325/325), 61.47 KiB, done.
Resolving deltas: 100% (110/110), done.
From https://hostname.org/vim-plugins.git
* branch master -> FETCH_HEAD
Added dir '.vim/bundle/vim-double-upon'Esto crea un commit de merge compactando todo el historial del subproyecto en uno solo:
3bca0ad [4 minutes ago] (HEAD, stree) Merge commit 'fa2f5dc4f1b94356bca8a440c786a94f75dc0a45' as '.vim/bundle/vim-double-upon' [John Brown]
fa2f5dc [4 minutes ago] Squashed '.vim/bundle/vim-double-upon/' content from commit 13189ec [John Brown]Para actualizar el código del plugin desde el repositorio upstream, haz un git subtree pull:
git subtree pull --prefix .vim/bundle/vim-double-upon https://hostname.org/example/vim-plugins.git master --squashPara contribuir con cambios de vuelta al repositorio upstream, extrae el historial del subtree usando git subtree split:
git subtree split --prefix .vim/bundle/vim-double-upon -b split-branch
git push split-branchEsto crea una nueva rama que contiene solo el historial del subtree, que luego puede enviarse al repositorio upstream.
Para hacer los comandos más cortos, añade el subproyecto como remoto.
Añadir el subproyecto como remoto
Añadirlo como remoto acorta el proceso:
git remote add -f vim-double-upon https://hostname.org/example/vim-plugins.gitAñade el subtree:
git subtree add --prefix .vim/bundle/vim-double-upon vim-double-upon master --squashActualiza el subproyecto así:
git fetch vim-double-upon master
git subtree pull --prefix .vim/bundle/vim-double-upon vim-double-upon master --squashGit Subtree es una alternativa a los submodules. Mientras que los submodules colocan otro proyecto en un directorio y mantienen sincronizado el repositorio remoto, Git Subtree mantiene el subproyecto como un directorio normal. Contribuir cambios de vuelta al repositorio upstream requiere usar git subtree split para extraer el historial del subproyecto, ya que la sincronización bidireccional directa no está soportada de forma nativa.
Practice
What are the features and usage of Git subtree?