1 == Secretos Revelados ==
3 Tomemos un vistazo bajo la mesa y expliquemos cómo realiza sus milagros. No escatimare sobre los detalles. Para descripciones detalladas referirse a http://schacon.github.com/git/user-manual.html[el manual de usuario].
7 ¿Cómo puede ser Git tan discreto? Aparte de los "commit" y "merge" ocasionales, usted puede trabajar inconscientemente de que un control de versiones existe. Esto sucede hasta que usted lo necesita, y esto es cuando esta agradecido de que Git este viendo por usted todo el tiempo.
9 Otros sistemas de control de versiones te fuerzan a luchar constantemente con cinta roja y burocracia. Los permisos de archivos podría ser de solo lectura a menos que usted explícitamente le diga a un servidor central cuales archivos intenta editar. Los comandos más básicos podrían retardarse al punto de arrastrarse cuando el número de usuarios se incrementa. El trabajo se paraliza cuando la red o el servidor central deja de funcionar.
11 En contraste, Git simplemente mantiene la historia de su proyecto en el directorio '.git' ubicado en su directorio de trabajo. Ésta es su propia copia de la historia, de esta manera usted puede trabajar desconectado hasta que desee comunicarse con otros. Usted tiene control total del destino de sus archivos ya que Git puede fácilmente recrear un estado guardado de '.git' en cualquier momento.
15 Muchas personas asocian criptografía con manterner la información secreta, pero otro objetivo importante es mantener la información segura. El uso apropiado de las funciones "hash" en criptografía puede prevenir corrupción de datos accidental o intencional.
17 Un hash SHA1 puede pensarse como un identificador numérico único de 160-bit para cualquier linea de caracteres que usted pueda encontrar en su vida. Pero mas que eso: cualquier linea de caracteres que cualquier ser humano vaya a usar en muchas vidas.
19 Como un "hash" SHA1 es una linea de "bytes", podemos dividir lineas de "bytes" que contienen otros "hash". Esta simple observación es sorpresivamente útil: buscar 'cadenas de "hash"'. Mas adelante veremos como Git lo utiliza para garantizar eficientemente la integridad de datos.
21 Brevemente, Git mantiene sus datos en el subdirectorio '.git/objects', donde en lugar de archivos normales, usted encontrara solo identificadores. Al usar identificadores como nombres de archivos, asi como algunos trucos de bloqueo de archivos y sellos de tiempo, Git transforma cualquier humilde sistema de archivos en una eficiente y robusta base de datos.
25 ¿Cómo sabe Git que usted renombró un archivo, incluso pensando que usted nunca menciono el hecho explícitamente? Seguramente, usted podria haber ejecutado *git mv*, pero eso es exactamente lo mismo a *git rm* seguido de *git add*.
27 Git heuristicamente averigua los cambios de nombre y copias entre versiones sucesivas. ¡De hecho, puede detectar pedazos de codigo que estan siendo movidos o copiados entre archivos! Al pensar que no puede cubrir todos los casos, realiza un trabajo decente, y esta caracteristica esta siendo mejorada constantemente. Si falla al trabajar por usted, intente habilitar deteccion de copias mas caras y considere actualizar.
31 Para cada archivo rastreado, Git guarda informacion como su tamano, fecha de creacion y ultima fecha de modificacion en un archivo conocido como 'index'. Para determinar cuando un archivo ha cambiado, Git compara su estado actual con lo que estan acumulados en el indice. Si son iguales, entonces Git omite leer el archivo nuevamente.
33 Partiendo del hecho de que las llamadas de estado son considerablemente mas rapidas que leer archivos, si usted edita unicamente
34 algunos archivos, Git puede actualizar su estado en casi nada de tiempo.
36 Hemos insistido anteriormente que el indice es un area de escenificacion. ¿Porque un monton de estados
37 de archivo es un area de escenificacion? Porque el comando "add" pone archivos en la based de datos de Git
38 y actualiza los estados, mientras que el comando "commit", sin opciones, crea una
39 actualizacion basada unicamente en estos estados y los archivos que ya estan en la base de datos.
41 === Los origenes de Git ===
43 Esto http://lkml.org/lkml/2005/4/6/121[ anuncio: Lista de Correos de "Linux Kernel"] Describe la cadena de eventos que llevaron a Git. El hilo entero es un fascinante sitio para los historiadores de Git.
45 === La Base de Datos de Objetos ===
47 Toda version de sus datos is mantenida en la "Base de Datos de Objetos", la cual vive en el
48 subdirectorio 'git./objects'; los otros residentes de '.git' mantienen menos datos:
49 el indice, nombres de ramas, etiquetas, opciones de configuracion, logs, la localizacion
50 actual del primer "commit", y asi sucesivamente. La Base de Datos de Objetos is elemental pero
51 elegante, y la fuente del poder de Git.
53 Cada archivo que se encuentre en '.git/objects' es un 'objeto'. Existen 3 tipos de objetos
54 que nos concierne: objetos 'blob', objetos 'tree', y objetos 'commit'.
58 Primero, un truco magico. Elija un archivo, cualquier archivo. En un directorio vacio:
60 $ echo sweet > NOMBRE_DE_ARCHIVO
63 $ find .git/objects -type f
65 Usted podra ver +.git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d+.
67 ¿Cómo se esto sin saber el nombre del archivo? Es porque el
70 "blob" SP "6" NUL "sweet" LF
72 es aa823728ea7d592acc69b36875a482cdf3fd5c8d,
73 donde SP es un espacio, NUL es un "byte" zero y LF es un avance de linea. Usted puede verificar
76 $ printf "blob 6\000sweet\n" | sha1sum
78 Git es 'contenido-direccionable': los archivos no son almacenados de acuerdo con su nombre,
79 sino mas por el "hash" de la informacion que contiene, dentro de un archivo llamamos al 'objeto
80 "blob"'. Podemos pensar de un "hash" como el identificador del contenido de un archivo, asi
81 que en un sentido estamos buscando archivos por su contenido. El "blob" inicial es
82 meramente un encabezado que consiste en el typo del objeto y su tamaño en "bytes"; lo que
83 simplifica la contabilidad interna.
85 De esta manera yo puedo predecir fácilmente lo que usted vera. El nombre del archivo es irrelevante:
86 solo la información interna es usada para construir el 'objeto "blob"'.
88 Usted podría estarse preguntando qué sucede con archivos idénticos. Intente agregar copias de
89 su archivo, con cualquier cosa de nombre. El contenido de +.git/objects+ se queda
90 de la misma manera sin importar cuantos agregue. Git guarda la información solo una vez.
92 Por cierto, los archivos ubicados en +.git/objects+ estan comprimidos con zlib asi que usted
93 no debería poder verlos directamente. Filtrelos a través de
94 http://www.zlib.net/zpipe.c[zpipe -d], o digite:
96 $ git cat-file -p aa823728ea7d592acc69b36875a482cdf3fd5c8d
98 lo que bellamente imprime el objeto dado.
102 ¿Pero dónde están los nombres de archivo? Ellos deberían estar almacenados en algún lugar en algún organizador.
103 Git toma su turno para poner los nombres de archivo durante un "commit":
105 $ git commit # Escribe algún mensaje.
106 $ find .git/objects -type f
108 Ahora debería poder ver 3 objetos. Esta vez no puedo decirte qué son esos 2 nuevos archivos, esto debende parcialmente del nombre de archivo que escogió. Procederemos asumiendo que eligió 'rose'. Si usted no lo hizo, podría reescribir la historia para hacer parecer que usted lo hizo:
110 $ git filter-branch --tree-filter 'mv YOUR_FILENAME rose'
111 $ find .git/objects -type f
113 Ahora debería poder ver el archivo
114 +.git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9+, porque este es el
115 SHA1 "hash" de su contenido:
117 "tree" SP "32" NUL "100644 rose" NUL 0xaa823728ea7d592acc69b36875a482cdf3fd5c8d
119 Verifique que este archivo contiene verdaderamente lo anterior escribiendo:
121 $ echo 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | git cat-file --batch
123 Con zpipe, es fácil verificar el hash:
125 $ zpipe -d < .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | sha1sum
127 Las verficaciones de "hash" son mas difíciles utilizando cat-file porque su salida contiene más
128 que la fuente del objeto del archivo descomprimido.
130 Este archivo es un objeto "tree": una lista de tuplas de un tipo de
131 archivo, un nombre de archivo, y un "hash". En nuestro ejemplo, el tipo de archivo es 100644, lo cual
132 significa que 'rose' es un archivo normal, y el "hash" es el objeto "blob" que contiene
133 los contenidos de 'rose'. Otro posible tipo de archivo son los ejecutables, enlaces simbólicos o
134 los directorios. En el último caso, los punteros "hash" a un objeto 'tree'.
136 Si usted ejecuta "filter-branch", obtendrá objetos viejos que ya no necesita. Aunque
137 serán desechados automáticamente una vez que su periodo de gracia expire, nosotros
138 los borraremos ahora para hacer nuestro ejemplo de prueba más fácil de seguir:
140 $ rm -r .git/refs/original
141 $ git reflog expire --expire=now --all
144 Para proyectos reales típicamente usted debería evitar comandos como este, ya que está
145 destruyendo respaldos. Si usted quiere un repositorio limpio, usualmente es mejor crear
146 un clon nuevo. También, tenga cuidado cuando está manipulando directamente +.git+: ¿qué pasaría si un proceso
147 Git está corriendo al mismo tiempo, ó un corte eléctrico ocurre?
148 En general, las referencias deberían ser eliminadas con *git update-ref -d*,
149 pensando que usualmente es más seguro remover +refs/original+ a mano.
153 Hemos explicado 2 de 3 objetos. El tercero es un objeto '"commit"'. Sus
154 contenidos dependen del mensaje del "commit" así como de la fecha en el que fué
155 creado. Para contrastar lo que tenemos aquí, deberemos torcerlo un poco:
157 $ git commit --amend -m Shakespeare # Change the commit message.
158 $ git filter-branch --env-filter 'export
159 GIT_AUTHOR_DATE="Fri 13 Feb 2009 15:31:30 -0800"
160 GIT_AUTHOR_NAME="Alice"
161 GIT_AUTHOR_EMAIL="alice@example.com"
162 GIT_COMMITTER_DATE="Fri, 13 Feb 2009 15:31:30 -0800"
163 GIT_COMMITTER_NAME="Bob"
164 GIT_COMMITTER_EMAIL="bob@example.com"' # Rig timestamps and authors.
165 $ find .git/objects -type f
168 +.git/objects/49/993fe130c4b3bf24857a15d7969c396b7bc187+
172 "tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9" LF
173 "author Alice <alice@example.com> 1234567890 -0800" LF
174 "committer Bob <bob@example.com> 1234567890 -0800" LF
178 Como antes, usted puede correr zpipe ó cat-file para que vea por usted mismo.
180 Este es el primer "commit", así que no existe un "commit" padre, pero "commit" sucesivos}
181 siempre van a contener al menos una línea identificando el "commit" padre.
183 === Sin Distinción de la Magia ===
185 Los secretos de Git parecen muy simples. Parece ser que usted podría unir algunos comandos y agregar una parte de código C para cocinar algo en cuestión de horas: una mezcla de operaciones básicas con archivos de sistema y SHA1 "hashing", adornado con archivos "lock" y "fsyncs" para robustez. De hecho, esto describe con exactitud las versiones anteriores de Git. Sin embargo, fuera de ingeniosos trucos de empaque para salvar espacio, e ingeniosos trucos de indexación para salvar tiempo, nosotros ahora sabemos definitivamente cómo Git cambia los sistemas de archivo en una base de datos perfecta para el control de versiones.
187 Por ejemplo, si cualquier archivo dentro de la base de datos es corrompido por un error
188 de disco, entonces su "hash" nunca más podrá ser emparejado, alertándonos del problema. Al
189 crear un "hash" de otros "hash" de otros objetos, mantenemos la integridad a todos los niveles. Los "commit"
190 son atómicos, eso es, un "commit" nunca puede guardar solamente partes de cambios: nosotros podemos
191 únicamente calcular el "hash" de un "commit" y guardarlo en la base de datos después de que ya
192 hemos guardado todos los árboles relevantes, los "blob" y los "commit" padres. La base de datos
193 de objetos es inmune a interrupciones inesperadas como cortes de electricidad.
195 Hemos derrotado inclusive al más tortuoso adversario. Suponga que alguien intenta
196 modificar furtivamente los contenidos de un archivo en una versión anterior de un proyecto. Para
197 mantener la base de datos de objetos sana, ellos deben cambiar también el "hash" del
198 objeto "blob" correspondiente porque ahora es una cadena de bytes distinta. Esto
199 significa que además tendrán que cambiar el "hash" de cualquier árbol de objetos referenciando el archivo,
200 y por defecto cambiar todos los "hash" de todos los descendientes del árbol de ese "commit". Además
201 de todos los "hash" de todos los descendientes de ese "commit".Esto implica que
202 el "hash" de la cabeza oficial difiere a la del repositorio erróneo. Para
203 seguir el curso de los "hash" que difieren podemos localizar el archivo mutilado,
204 así como el "commit" en donde fue corrompido inicialmente.
206 En corto tiempo, mientras que los 20 "byte" representando el último "commit" seguro,
207 es imposible de manosear en un repositorio de Git.
209 ¿Qué sucede con las famosas características de Git? ¿Las ramas? ¿Las mezclas? ¿Los tags?
210 Simples detalles. La cabeza actual es mantenida en el archivo +.git/HEAD+,
211 la cual contiene un "hash" de un objeto "commit". El "hash" es actualizado durante un "commit"
212 así como cualquier otro comando. Las ramas son casi lo mismo: son archivos en
213 +.git/refs/heads+. Las etiquetas también: se encuentran en +.git/refs/tags+ pero
214 son actualizadas por un juego de comandos distintos.