Saltar al contenido

¿Cómo se almacenan las ramas y etiquetas de git en los discos?

Bienvenido a nuestra comunidad, ahora encontrarás la respuesta que estabas buscando.

Solución:

Entonces, voy a ampliar un poco el tema y explicar cómo Tiendas Git qué. Al hacerlo, se explicará qué información se almacena y qué es exactamente lo que importa para el tamaño del repositorio. Como una advertencia justa: esta respuesta es bastante larga 🙂

Objetos Git

Git es esencialmente una base de datos de objetos. Esos objetos vienen en cuatro tipos diferentes y todos se identifican mediante un hash SHA1 de su contenido. Los cuatro tipos son manchas, árboles, comete y etiquetas.

Gota

A gota es el tipo de objeto más simple. Almacena el contenido de un archivo. Por lo tanto, para cada contenido de archivo que almacena en su repositorio de Git, existe un único objeto blob en la base de datos de objetos. Como solo almacena el archivo contenido, y no metadatos como nombres de archivos, este es también el mecanismo que evita que los archivos con contenido idéntico se almacenen varias veces.

Árbol

Subiendo un nivel, el árbol es el objeto que coloca los blobs en una estructura de directorio. Un solo árbol corresponde a un solo directorio. Es esencialmente una lista de archivos y subdirectorios, con cada entrada que contiene un modo de archivo, un nombre de archivo o directorio y una referencia al objeto Git que pertenece a la entrada. Para los subdirectorios, esta referencia apunta al objeto de árbol que describe el subdirectorio; para los archivos, esta referencia apunta al objeto blob que almacena el contenido del archivo.

Cometer

Las manchas y los árboles ya son suficientes para representar un sistema de archivos completo. Para agregar el control de versiones además de eso, tenemos cometer objetos. Los objetos de confirmación se crean cada vez que confirma algo en Git. Cada confirmación representa una instantánea del historial de revisiones.

Contiene una referencia al objeto de árbol que describe el directorio raíz del repositorio. Esto también significa que cada confirmación que realmente introduce algunos cambios requiere al menos un nuevo objeto de árbol (probablemente más).

Una confirmación también contiene una referencia a sus confirmaciones principales. Si bien generalmente hay un solo padre (para un historial lineal), una confirmación puede tener cualquier número de padres, en cuyo caso generalmente se llama fusionar compromiso. La mayoría de los flujos de trabajo solo te harán fusionar con dos padres, pero también puedes tener cualquier otro número.

Y finalmente, una confirmación también contiene los metadatos que espera que tenga una confirmación: autor y autor (nombre y hora) y, por supuesto, el mensaje de confirmación.

Eso es todo lo que se necesita para tener un sistema de control de versiones completo; pero, por supuesto, hay un tipo de objeto más:

Etiqueta

Los objetos de etiqueta son una forma de almacenar etiquetas. Para ser precisos, los objetos de etiqueta almacenan etiquetas anotadas, que son etiquetas que tienen, similar a las confirmaciones, algo de metainformación. Son creados por git tag -a (o al crear una etiqueta firmada) y requieren un mensaje de etiqueta. También contienen una referencia al objeto de confirmación al que apuntan y un etiquetador (nombre y hora).

Referencias

Hasta ahora, tenemos un sistema de control de versiones completo, con etiquetas anotadas, pero todos nuestros objetos están identificados por su hash SHA1. Eso, por supuesto, es un poco molesto de usar, así que tenemos algo más para hacerlo más fácil: Referencias.

Las referencias vienen en diferentes sabores, pero lo más importante de ellas es esto: son archivos de texto simples que contienen 40 caracteres: el hash SHA1 del objeto al que apuntan. Porque son así de simples, son muy barato, por lo que trabajar con muchas referencias no supone ningún problema. No crea gastos generales y no hay razón para no usarlos.

Por lo general, hay tres “tipos” de referencias: sucursales, etiquetas y sucursales remotas. Realmente funcionan igual y todos apuntan a cometer objetos; excepto por anotado etiquetas que apuntan a objetos de etiqueta (las etiquetas normales son solo referencias de confirmación). La diferencia entre ellos es cómo los crea y en qué subruta de /refs/ están almacenados. Sin embargo, no cubriré esto ahora, ya que esto se explica en casi todos los tutoriales de Git; solo recuerda: las referencias, es decir, las ramas, son extremadamente baratas, así que no dudes en crearlas para casi todo.

Compresión

Ahora, como torek mencionó algo sobre la compresión de Git en su respuesta, quiero aclarar esto un poco. Desafortunadamente él mixed algunas cosas arriba.

Entonces, generalmente para los nuevos repositorios, todos los objetos de Git se almacenan en .git/objects como archivos identificados por su hash SHA1. Los dos primeros caracteres se eliminan del nombre del archivo y se utilizan para dividir los archivos en varias carpetas, para que sea un poco más fácil navegar.

En algún momento, cuando el historial se haga más grande o cuando sea activado por otra cosa, Git comenzará a comprimir objetos. Lo hace empaquetando varios objetos en un solo paquete de archivo. Cómo funciona esto exactamente no es realmente tan importante; reducirá la cantidad de objetos Git individuales y los almacenará de manera eficiente en archivos individuales indexados (en este punto, Git usará compresión delta por cierto). Los archivos del paquete se almacenan en .git/objects/pack y puede obtener fácilmente unos cientos de MiB de tamaño.

Para referencias, la situación es algo similar, aunque mucho más sencilla. Todos Actual las referencias se almacenan en .git/refs, por ejemplo, sucursales en .git/refs/heads, etiquetas en .git/refs/tags y sucursales remotas en .git/refs/remotes/. Como se mencionó anteriormente, son archivos de texto simples que contienen solo el identificador de 40 caracteres del objeto al que apuntan.

En algún momento, Git moverá las referencias más antiguas, de cualquier tipo, a un solo archivo de búsqueda: .git/packed-refs. Ese archivo es solo una larga lista de hashes y nombres de referencia, una entrada por línea. Las referencias que se guardan allí se eliminan del refs directorio.

Reflogs

Torek también los mencionó, reflogs son esencialmente registros para referencias. Realizan un seguimiento de lo que sucede con las referencias. Si hace algo que afecte a una referencia (confirmar, retirar, restablecer, etc.), se agrega una nueva entrada de registro simplemente para registrar lo que sucedió. También proporciona una forma de retroceder después de haber hecho algo mal. Un caso de uso común, por ejemplo, es acceder al reflog después de restablecer accidentalmente una rama a un lugar al que no se suponía que debía ir. A continuación, puede utilizar git reflog para mirar el registro y ver hacia dónde apuntaba la referencia antes. Como los objetos sueltos de Git no se eliminan de inmediato (los objetos que forman parte del historial nunca se eliminan), generalmente puede restaurar la situación anterior fácilmente.

Sin embargo, los reflogs local: Solo realizan un seguimiento de lo que sucede en su repositorio local. No se comparten con controles remotos y nunca se transfieren. Un repositorio recién clonado tendrá un reflog con una sola entrada, que es la acción de clonar. También están limitados a una cierta longitud después de la cual se eliminan las acciones más antiguas, por lo que no se convertirán en un problema de almacenamiento.

Algunas palabras finales

Entonces, volviendo a tu pregunta real. Cuando clona un repositorio, Git generalmente ya recibirá el repositorio en un formato empaquetado. Esto ya está hecho para ahorrar tiempo de transferencia. Las referencias son muy baratas, por lo que nunca son la causa de grandes repositorios. Sin embargo, debido a la naturaleza de Git, un único objeto de confirmación actual tiene un gráfico acíclico completo que eventualmente alcanzará la primera confirmación, el primer árbol y el primer blob. Por lo tanto, un repositorio siempre contendrá toda la información de todas las revisiones. Eso es lo que hace que los repositorios con una larga historia sean grandes. Desafortunadamente, no hay mucho que puedas hacer al respecto. Bueno, podría cortar el historial anterior en alguna parte, pero eso lo dejará con un repositorio roto (lo hace clonando con el --depth parámetro).

Y en cuanto a su segunda pregunta, como expliqué anteriormente, las ramas son solo referencias a confirmaciones, y las referencias son solo punteros a objetos Git. Entonces no, realmente no hay metadatos sobre las ramas que pueda obtener de ellas. Lo único que podría darte una idea es el primer compromiso que hiciste al ramificarte en tu historial. Pero tener sucursales no significa automáticamente que haya una sucursal guardada en el historial (la fusión y el rebase rápido funcionan en su contra), y el hecho de que haya alguna sucursal en el historial no significa que la sucursal (el referencia, el puntero) todavía existe.

Todas las referencias de git (ramas, etiquetas, notas, escondites, etc.) usan el mismo sistema. Estos son:

  • las referencias mismas, y
  • “reflogs”

Los reflogs se almacenan en .git/logs/refs/ basado en el nombre de referencia, con una excepción: reflogs para HEAD están almacenados en .git/logs/HEAD en vez de .git/logs/refs/HEAD.

Las referencias vienen “sueltas” o “empaquetadas”. Los refs empaquetados están en .git/packed-refs, que es un archivo plano de pares (SHA-1, refname) para referencias simples, además de información adicional para etiquetas anotadas. Las referencias “sueltas” están en .git/refs/name. Estos archivos contienen un SHA-1 sin formato (probablemente el más común) o el literal string ref: seguido del nombre de otra referencia para referencias simbólicas (normalmente sólo para HEAD pero puedes hacer otros). Las referencias simbólicas no están empaquetadas (o al menos, parece que no puedo hacer que eso suceda :-)).

Las etiquetas de empaque y los cabezales de rama “inactivos” (aquellos que no se actualizan activamente) ahorran espacio y tiempo. Puedes usar git pack-refs para hacer esto. Sin embargo, git gc invoca git pack-refs para usted, por lo que generalmente no es necesario que lo haga usted mismo.

Aquí puedes ver las reseñas y valoraciones de los lectores

Finalizando este artículo puedes encontrar las aclaraciones de otros administradores, tú igualmente tienes la opción de mostrar el tuyo si lo deseas.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *