Cómo Funciona Git Bajo el Capó: Objetos, Árboles y Blobs
Usamos git add, git commit y git push todos los días. Pero, ¿alguna vez has mirado dentro de la carpeta .git?
Entender los componentes internos de Git desmitifica la "magia" y te convierte en un usuario mucho más seguro (¡y mejor arreglando conflictos de fusión!).
En su núcleo, Git es un sistema de archivos direccionable por contenido. Idealmente, es un almacén clave-valor donde:
- Clave: Hash SHA-1 del contenido.
- Valor: El contenido en sí.
Exploremos los tres objetos principales que Git usa para almacenar tu historial.
1. El Blob (Binary Large Object)
Cuando haces git add a un archivo, Git toma el contenido de ese archivo y lo almacena como un Blob.
- No almacena el nombre del archivo, solo el contenido.
- Si dos archivos tienen exactamente el mismo contenido, comparten el mismo Blob (¡deduplicación!).
Puedes ver esto con git cat-file:
$ echo "hello" | git hash-object -w --stdin ce013625030ba8dba906f756967f9e9ca394464a
Ese hash es la clave.
2. El Árbol (Tree)
Entonces, ¿dónde se almacenan los nombres de archivo? En un objeto Tree.
Un Árbol es como un directorio. Contiene una lista de:
- Permisos de archivo (ej.,
100644) - Tipo de objeto (
blobotree) - Hash SHA-1
- Nombre de archivo
Piensa en un Árbol como una instantánea de una estructura de carpetas.
100644 blob ce0136... hello.txt
100644 blob 9a8b7c... README.md
040000 tree 3b1c2d... src
3. El Commit
Finalmente, tenemos el objeto Commit.
Un commit es simplemente un envoltorio que apunta a un Tree específico (la instantánea del proyecto en ese momento) y añade metadatos:
- Autor y Committer
- Fecha
- Mensaje del Commit
- Hash del Commit Padre
Debido a que cada commit apunta a su padre, forman una lista enlazada (o más bien, un Grafo Acíclico Dirigido - DAG).
tree 3b1c2d...
parent 8a9b0c...
author John Doe <[email protected]>
committer John Doe <[email protected]>
Initial commit
Visualizando la Relación
graph TD subgraph Commit C[Objeto Commit] -->|Apunta a| T[Objeto Tree] C -->|Apunta a| P[Commit Padre] end subgraph Tree T -->|Contiene| B1[Blob: hello.txt] T -->|Contiene| B2[Blob: README.md] T -->|Contiene| T2[Tree: src] end subgraph Blob B1 -->|Contenido| Content1["hello"] B2 -->|Contenido| Content2["# Readme"] end
Poniéndolo Todo Junto
Cuando ejecutas git commit:
- Git crea Blobs para los archivos cambiados.
- Git crea un Tree representando la estructura del proyecto.
- Git crea un objeto Commit apuntando a ese Árbol y al commit anterior.
- El puntero de la rama (ej.,
main) se mueve a este nuevo hash de commit.
Por Qué Importa Esto
- Git es inmutable: Una vez que se crea un objeto, nunca cambia. "Modificar" el historial en realidad crea nuevos objetos.
- Ramificación barata: Una rama es solo un pequeño archivo de 40 bytes que contiene un hash de commit. Crear una rama no cuesta nada.
- Integridad: El hash SHA-1 asegura que si un solo bit de datos cambia, el ID cambia. Es imposible corromper el historial sin detección.
La próxima vez que estés atascado en el estado "detached HEAD", recuerda: ¡simplemente estás apuntando a un objeto Commit que no está etiquetado con un nombre de rama!
Explora herramientas relacionadas
Prueba estas herramientas gratuitas de Pockit