Aspectos destacados de Git 2.47
Git 2.47 ya está aquí, con funciones como índices multipaquete incrementales y más. Consulta nuestra cobertura de algunos de los aspectos más destacados aquí.
El proyecto de código abierto Git acaba de lanzar Git 2.47 con funciones y correcciones de errores de más de 83 colaboradores, 28 de ellos nuevos. La última vez que hablamos con usted sobre las últimas novedades de Git fue cuando se lanzó la versión 2.46 .
Para celebrar este lanzamiento más reciente, aquí presentamos el análisis de GitHub de algunas de las características y cambios más interesantes introducidos desde la última vez.
Índices multipack incrementales
Los lectores habituales de esta serie sin duda recordarán nuestra cobertura de todo lo relacionado con los índices multipack (MIDX). Si eres nuevo aquí o necesitas un repaso, aquí tienes un breve resumen.
Git almacena objetos (blobs, árboles, commits y etiquetas que conforman el contenido de tu repositorio) en uno de dos formatos: sueltos o empaquetados. Los objetos sueltos son los archivos individuales almacenados en los subdirectorios de dos caracteres de $GIT_DIR/objects, cada uno de los cuales representa un fragmento del conjunto total de objetos sueltos. Por ejemplo, el objeto 08103b9f2b6e7fbed517a7e268e4e371d84a9a10se almacenaría suelto en $GIT_DIR/objects/08/103b9f2b6e7fbed517a7e268e4e371d84a9a10.
Los objetos también se pueden empaquetar juntos en un único archivo conocido como packfile . Los packfiles almacenan varios objetos juntos en un formato binario, lo que tiene un par de ventajas sobre el almacenamiento de objetos sueltos. Los packfiles suelen tener una mejor localización de la caché porque los objetos similares suelen empaquetarse uno al lado del otro o cerca de él. Los packfiles también tienen la ventaja de poder representar objetos como deltas entre sí, lo que permite una representación más compacta de pares de objetos similares.
Sin embargo, los repositorios pueden comenzar a experimentar un rendimiento deficiente cuando acumulan muchos archivos de paquetes, ya que Git tiene que buscar en cada archivo de paquetes para realizar cada búsqueda de objetos. Para mejorar el rendimiento cuando un repositorio acumula demasiados paquetes, un repositorio debe volver a empaquetar para generar un solo paquete nuevo que contenga el contenido combinado de todos los paquetes existentes. Esto deja al repositorio con un solo paquete (lo que da como resultado tiempos de búsqueda más rápidos), pero el costo de generar ese paquete puede ser alto.
En Git 2.21, se introdujeron los índices de múltiples paquetes para mitigar este gasto. Los MIDX son una asignación de índice entre los objetos del paquete y la ubicación dentro de ese paquete en la que aparecen. Debido a que los MIDX pueden almacenar información sobre objetos en varios paquetes, permiten búsquedas rápidas de objetos para repositorios que tienen muchos paquetes individuales, como se muestra a continuación:
Aquí, el índice de paquetes múltiples se muestra como una serie de rectángulos de colores, cada uno de los cuales representa un objeto. Las flechas señalan la ubicación de esos objetos dentro del paquete del que fueron seleccionados en el MIDX y codifican la información almacenada en el propio MIDX.
Pero generar y actualizar el MIDX del repositorio también lleva tiempo: cada objeto de los paquetes que forman parte del MIDX debe examinarse para registrar su ID de objeto y desplazamiento dentro de su paquete de origen. Este tiempo puede extenderse aún más si está utilizando mapas de bits de accesibilidad de paquetes múltiples , ya que agrega una cantidad potencialmente grande de recorridos que cubren porciones significativas del repositorio al tiempo de ejecución.
Entonces, ¿qué se puede hacer? Reempaquetar el repositorio para optimizar las búsquedas de objetos puede ser un proceso lento, pero también lo puede ser actualizar el índice de paquetes múltiples del repositorio.
Git 2.47 presenta una nueva característica experimental conocida como índices multipaquete incrementales, que permiten almacenar más de un índice multipaquete juntos en una cadena de capas MIDX. Cada capa contiene paquetes y objetos que son distintos de las capas anteriores, por lo que el MIDX se puede actualizar rápidamente mediante una operación de anexión que solo toma tiempo proporcional a los nuevos objetos que se agregan, no al tamaño del MIDX general. A continuación, se muestra un ejemplo:
La primera mitad de la figura es la misma que la anterior, pero la segunda mitad muestra una nueva capa incremental en la cadena de índices de paquetes múltiples. Los objetos contenidos en el MIDX de la segunda mitad son exclusivos de los de la primera mitad. Pero tenga en cuenta que los paquetes de origen que aparecen en el MIDX de la segunda mitad tienen cierta superposición con los objetos que aparecen en el MIDX de la primera mitad.
En Git 2.47, la función de índice multipaquete incremental aún se considera experimental y aún no admite mapas de bits de accesibilidad multipaquete. Sin embargo, la compatibilidad con mapas de bits multipaquete incrementales está actualmente en revisión y, con suerte, aparecerá en una versión futura.
(En GitHub, planeamos usar mapas de bits multipaquete incrementales como parte de mayores esfuerzos de escalamiento para soportar repositorios aún más grandes durante el mantenimiento del repositorio. Cuando lo hagamos, esperamos publicar una publicación en nuestro blog que cubra los detalles).
Puedes experimentar con índices multipaquete incrementales ejecutando:
$ git multi-pack-index write --incremental
para agregar nuevos paquetes al MIDX existente de su repositorio hoy.
Encuentre rápidamente ramas base confor-each-ref
¿Alguna vez has estado trabajando en una rama o explorando una nueva base de código y te has preguntado: "¿En qué se basa esta rama?" Es una pregunta común, pero la respuesta puede ser sorprendentemente difícil de responder con las herramientas que existían anteriormente.
Una buena aproximación para determinar qué rama fue el punto de inicio probable para alguna confirmación C es seleccionar la rama que minimiza las confirmaciones del primer padre que son exclusivas de C. (Aquí, las "confirmaciones del primer padre" son las confirmaciones a las que se puede llegar simplemente recorriendo el primer padre de una confirmación de fusión en lugar de atravesar todos sus padres).
Si te preguntas: "¿por qué limitar el recorrido al historial del primer padre?", la respuesta es porque el historial del primer padre refleja la ruta principal a través del historial que conduce a una confirmación. Al minimizar la cantidad de confirmaciones únicas del primer padre entre un conjunto de ramas base candidatas, esencialmente estás buscando aquella cuya ruta de desarrollo principal sea la más cercana a la confirmación C. Por lo tanto, la rama con la menor cantidad de confirmaciones únicas del primer padre es probablemente donde se originó C o desde donde se ramificó.
Podrías pensar que podrías usar algo como git rev-list --count --first-parentcontar la cantidad de confirmaciones del primer padre entre dos puntos finales. Pero ese no es exactamente el caso, ya que rev-list eliminará todas las confirmaciones alcanzables desde la base antes de devolver el recuento único.
Git 2.47 presenta una nueva herramienta para determinar qué rama fue el punto de partida probable para alguna confirmación a través de un nuevo átomo utilizado en la especificación for-each-refde --format. Por ejemplo, digamos que estoy tratando de determinar qué nombre de rama se eligió para un tema en el que trabajé en sentido ascendente.
$ needle=fcb2205b77470c60f996a3206b2d4aebf6e951e3
$ git for-each-ref --contains $needle refs/remotes/origin | wc -l
63
La búsqueda ingenua del conjunto de ramas que contienen lo que busco puede devolver muchos resultados, por ejemplo, si mi confirmación se fusionó y ahora está contenida en muchas otras ramas. Pero el nuevo %(is-base:átomo ) puede producir la respuesta correcta:
$ git for-each-ref --format="%(refname) %(is-base:$needle)" refs/remotes/origin \
| grep '('
refs/remotes/origin/tb/incremental-midx-part-1 (fcb2205b77470c60f996a3206b2d4aebf6e951e3)
Git es conocido por su portabilidad y compatibilidad con una amplia variedad de sistemas y arquitecturas, incluidas algunas bastante exóticas. Sin embargo, hasta esta versión más reciente, Git carecía de una política formal de compatibilidad con plataformas. Esta versión incluye un nuevo documento de “ Política de compatibilidad de plataformas ” que describe la política oficial de Git al respecto. Los detalles exactos se pueden encontrar en el enlace de origen que aparece a continuación, pero la idea básica actual es que las plataformas deben tener C99 o C11 , usar versiones de dependencias que sean estables o tengan compatibilidad a largo plazo y deben tener un sistema de compatibilidad de seguridad activo. Se están llevando a cabo debates sobre la posibilidad de agregar requisitos adicionales, incluida la posibilidad de depender de Rust en una versión futura. La política también contiene sugerencias para los mantenedores de la plataforma sobre qué ramas probar y cómo informar y solucionar problemas de compatibilidad.
Hace un par de lanzamientos, analizamos el soporte preliminar de Git para un nuevo backend de referencia conocido como reftable . Si no estás seguro de los detalles, nuestra publicación anterior está repleta de ellos. Esta versión incorpora una serie de pruebas unitarias que se escribieron en el marco de pruebas personalizado de la implementación de reftable al marco de pruebas unitarias estándar de Git. Estas migraciones fueron realizadas por Chandra Pratap, uno de los colaboradores de Google Summer of Code (GSoC) del proyecto Git . En esta versión, reftable también obtuvo un mejor soporte al trabajar con escritores simultáneos, en particular durante la compactación de la pila. El backend de reftable también obtuvo soporte para la opción –exclude de Git for-each-ref, sobre la que escribimos cuando se lanzó Git 2.42 .
Mientras estamos en el tema de pruebas unitarias, hubo varias otras áreas del proyecto que recibieron una cobertura de pruebas unitarias más exhaustiva o que migraron pruebas existentes desde el conjunto de pruebas de integración basadas en Shell de Git. Las funciones de normalización de URLmatch, la matriz OID y la API de mapas hash de Git se convirtieron de pruebas basadas en Shell con ayudantes personalizados a pruebas unitarias. El marco de pruebas unitarias en sí también recibió una atención significativa, lo que finalmente resultó en el uso del marco Clar , que originalmente se escribió para reemplazar el marco de pruebas unitarias en libgit2. Muchas de estas conversiones de pruebas unitarias fueron realizadas por Ghanshyam Thakkar, otro de los colaboradores de GSoC de Git .
Mientras hablamos de los colaboradores de Google Summer of Code, deberíamos mencionar por último (¡pero no por ello menos importante!) a otro estudiante, shejialuo , que mejoró git fsckla verificación de la integridad del backend de almacenamiento de referencia además del almacén de objetos habitual. Introdujeron un nuevo git refs verifysubcomando que se ejecuta a través de via git fscky detecta muchos problemas de corrupción de referencias.
Desde al menos 2019 , se ha hecho un esfuerzo por encontrar y anotar parámetros no utilizados en funciones en todo el código base de Git. Anotar parámetros como no utilizados puede ayudar a identificar mejores API y, a menudo, la presencia de un parámetro no utilizado puede señalar un error legítimo en la implementación de esa función. Durante muchos años, el proyecto Git ha intentado compilar con -Wunused-parametersu modo especial DEVELOPER=1, lo que hace que sea un error en tiempo de compilación tener o introducir parámetros no utilizados en el código base. Durante ese tiempo, se han realizado muchas correcciones y limpiezas de parámetros no utilizados, todo ello mientras se trabajaba en otros desarrollos activos en áreas relacionadas. En esta versión, ese esfuerzo llegó a su fin. Ahora, al compilar con DEVELOPER=1, es un error en tiempo de compilación tener parámetros sin usar, lo que hace que la base de código de Git sea más limpia y segura en el futuro.
Cuando se lanzó Git 2.34 , cubrimos un esfuerzo creciente para encontrar y reparar fugas de memoria en todo el código base de Git. En ese entonces, escribimos que, dado que Git normalmente tiene un tiempo de ejecución muy corto, es mucho menos urgente liberar memoria que, por ejemplo, en el código de la biblioteca, ya que el sistema operativo "liberará" la memoria de un proceso cuando el proceso se detenga. Pero a medida que los componentes internos de Git continúan reformándose con el objetivo final de que puedan llamarse como una biblioteca de primera parte, tapar cualquier fuga de memoria en todo el código base es de vital importancia. Ese esfuerzo ha continuado en esta versión, y se han solucionado más filtraciones en todo el código base.
El git mergetoolcomando aprendió una nueva configuración de herramientas para Visual Studio Code. Si bien siempre fue posible configurar manualmente Git para ejecutar la resolución de combinación de tres vías de VSCode, requería una configuración manual. En Git 2.47, ahora puedes configurar fácilmente tu repositorio ejecutando:
$ git config set merge.tool vscode
y las ejecuciones posteriores de git mergetool abrirán automáticamente VSCode en la configuración correcta.
Senior QA Automation Engineer at Endava
6 díasPara actualizar GIT a la última versión en Windows, solo abre Terminal y ejecuta el comando: git update-git-for-windows