¡Saludos, Agentes Geek! El proyecto de código abierto Git ha lanzado su versión 2.51, trayendo consigo un conjunto de nuevas características y correcciones de errores gracias a la contribución de más de 91 desarrolladores, ¡21 de ellos nuevos en el proyecto!
En esta ocasión, echaremos un vistazo a algunas de las funcionalidades y cambios más interesantes que incluye esta última versión.
Índices Multi-Pack Libres de ‘Cruft’
Si ya estás familiarizado con el mundo de Git, es probable que hayas oído hablar de los ‘cruft packs’, los índices multi-pack (MIDX) y los ‘reachability bitmaps’. Pero, por si acaso necesitas un repaso, aquí tienes un breve resumen:
Git almacena el contenido del repositorio como ‘objetos’ (blobs, árboles, commits), ya sea individualmente (objetos ‘loose’, como $GIT_DIR/objects/08/10d6a05...) o agrupados en ‘packfiles’ ($GIT_DIR/objects/pack). Cada pack tiene un índice (*.idx) que mapea los hashes de los objetos a los offsets. Cuando tienes muchos packs, las búsquedas se ralentizan a O(M*log(N)), donde M es el número de packs en tu repositorio y N es el número de objetos dentro de un pack determinado.
Un MIDX funciona como un índice de pack, pero cubre los objetos a través de múltiples packfiles individuales, lo que reduce el costo de búsqueda a O(log(N)), donde N es el número total de objetos en tu repositorio. En GitHub, los MIDX se utilizan para almacenar el contenido de tu repositorio después de dividirlo en varios packs, así como para almacenar una colección de ‘reachability bitmaps’ para determinar rápidamente qué objetos son accesibles desde un commit dado.
Los ‘cruft packs’ se utilizan para almacenar objetos inalcanzables por separado. Originalmente, se pretendía excluir estos objetos del MIDX, pero esto resultó ser imposible. La razón principal es que si un objeto que antes era inalcanzable (almacenado en un ‘cruft pack’) luego se vuelve alcanzable desde un commit ‘bitmapped’, pero la única copia de ese objeto se encuentra en un ‘cruft pack’ fuera del MIDX, entonces ese objeto no tiene una posición de bit, lo que imposibilita la escritura de un ‘reachability bitmap’.
Git 2.51 introduce un cambio en la forma en que se empaqueta la porción no-‘cruft’ de tu repositorio. Al generar un nuevo pack, Git solía excluir cualquier objeto que apareciera en al menos un pack que no se eliminaría durante una operación de ‘repack’, incluyendo los ‘cruft packs’. En la versión 2.51, Git ahora almacenará copias adicionales de los objetos (y sus ancestros) cuya única otra copia se encuentre dentro de un ‘cruft pack’. Este proceso garantiza que el conjunto de packs no-‘cruft’ no tenga ningún objeto que alcance a otro objeto no almacenado dentro de ese conjunto de packs.
Como resultado, Git 2.51 introduce una nueva configuración, repack.MIDXMustContainCruft, que utiliza el nuevo comportamiento de ‘repacking’ para almacenar los ‘cruft packs’ fuera del MIDX. En GitHub, esto ha permitido escribir MIDX significativamente más pequeños, en una fracción del tiempo, lo que se traduce en un rendimiento de lectura del repositorio más rápido en general. (En su monorepo principal, los MIDX se redujeron en aproximadamente un 38%, se escribieron un 35% más rápido y se mejoró el rendimiento de lectura en alrededor de un 5%).
Puedes probar los MIDX sin ‘cruft’ utilizando la nueva opción de configuración repack.MIDXMustContainCruft.
Packs Más Pequeños con ‘Path Walk’
En Git 2.49, se introdujo la característica ‘name-hash v2’, que cambió la forma en que Git selecciona pares de objetos para la compresión delta. Cuando se prepara un packfile, Git calcula un hash de todos los objetos basándose en su ruta de archivo. Esos hashes se utilizan para ordenar la lista de objetos a empaquetar, y Git utiliza una ventana deslizante para buscar entre pares de objetos e identificar buenos candidatos delta/base.
Anteriormente, Git utilizaba una única función hash basada en la ruta del objeto, con un fuerte sesgo hacia los últimos 16 caracteres de la ruta. Git 2.49 introdujo una nueva función hash que tiene más en cuenta la estructura del directorio, lo que resulta en packs significativamente más pequeños en algunas circunstancias.
Git 2.51 va un paso más allá al introducir una nueva forma de recopilar objetos al hacer ‘repacking’, llamada ‘path walk’. En lugar de recorrer los objetos en orden de revisión, emitiendo objetos con sus nombres de ruta correspondientes, el enfoque ‘path walk’ emite todos los objetos de una ruta dada al mismo tiempo. Este enfoque evita por completo la heurística ‘name-hash’ y puede buscar deltas dentro de grupos de objetos que se sabe que están en la misma ruta.
Como resultado, Git puede generar packs utilizando el enfoque ‘path walk’ que a menudo son significativamente más pequeños que incluso aquellos generados con la nueva función hash de nombre descrita anteriormente. Sus tiempos son competitivos incluso con la generación de packs utilizando el recorrido de orden de revisión existente.
Puedes probarlo haciendo ‘repacking’ con la nueva opción de línea de comandos --path-walk.
Formato de Intercambio de Stash
Si alguna vez has necesitado cambiar a otra rama, pero querías guardar los cambios no commitados, es probable que hayas usado git stash. Este comando guarda el estado de tu copia de trabajo y del índice, y luego restaura tu copia local para que coincida con lo que había en HEAD en el momento en que hiciste el ‘stash’.
Cuando haces un ‘stash’, Git crea tres commits detrás de escena. Dos commits capturan los cambios ‘staged’ y ‘unstaged’. Los cambios ‘staged’ representan lo que estaba en tu índice en el momento de hacer el ‘stash’, y los cambios del directorio de trabajo representan todo lo que cambiaste en tu copia local pero no agregaste al índice. Finalmente, Git crea un tercer commit que lista los otros dos como sus padres, capturando la instantánea completa.
Estos commits generados internamente se almacenan en la referencia especial refs/stash, y múltiples entradas de ‘stash’ se gestionan con el ‘reflog’. Se puede acceder a ellos con git stash list, etc. Dado que solo hay una entrada de ‘stash’ en refs/stash a la vez, es extremadamente engorroso migrar entradas de ‘stash’ de una máquina a otra.
Git 2.51 introduce una variante de la representación interna del ‘stash’ que permite representar múltiples entradas de ‘stash’ como una secuencia de commits. En lugar de utilizar los dos primeros padres para almacenar los cambios del índice y la copia de trabajo, esta nueva representación agrega un padre más para referirse a la entrada de ‘stash’ anterior. Esto da como resultado entradas de ‘stash’ que contienen cuatro padres y pueden tratarse como un registro ordinario de commits.
Como consecuencia de esto, ahora puedes exportar tus ‘stashes’ a una sola referencia, y luego hacer ‘push’ o ‘pull’ como lo harías con una rama o etiqueta normal. Git 2.51 facilita esto al introducir dos nuevos subcomandos a git stash para importar y exportar, respectivamente. Ahora puedes hacer algo como:
$ git stash export --to-ref refs/stashes/my-stash
$ git push origin refs/stashes/my-stash
en una máquina para subir el contenido de tu ‘stash’ a ‘origin’, y luego:
$ git fetch origin '+refs/stashes/*:refs/stashes/*'
$ git stash import refs/stashes/my-stash
en otra, preservando el contenido de tu ‘stash’ entre las dos.
Otras Novedades
Además de lo anterior, Git 2.51 también incluye:
- Mejoras en
git cat-filepara mostrar información de submódulos. - Soporte para múltiples pathspecs en filtros Bloom para optimizar recorridos del historial.
- Los comandos
git switchygit restoredejan de ser experimentales. - El comando
git whatchangedse marca como obsoleto. - Git 3.0 usará reftable como formato por defecto y SHA-256 como función hash.
- Actualizaciones en las guías de contribución para permitir parches con identidades diferentes al nombre legal.
Conclusión
Git 2.51 trae consigo una serie de mejoras y nuevas funcionalidades que optimizan el manejo de repositorios y el flujo de trabajo. Desde la gestión de ‘cruft packs’ hasta el nuevo formato de intercambio de ‘stashes’, esta versión ofrece herramientas valiosas para desarrolladores de todos los niveles. ¡No dudes en explorar estas novedades y aprovechar al máximo tu experiencia con Git!
Referencias: GitHub Blog
Leave a Comment