Git es un sistema al que se le puede sacar más provecho si se conoce la interacción entre sus componentes. Más allá de eso, comprender la simplicidad de sus estructuras de datos permite que uno se sienta agusto y, especialmente, en control de la herramienta.
Esto lo mencioné en el tutorial de Git que presenté en la reunión de febrero 2013 del Grupo de Usuarios de GNU/Linux de Tijuana. En general todo salió muy bien. Lo único que me hubiera gustado poder mostrar en vivo es el contenido de un objeto, un blob de Git que está dentro de .git/objects
.
Decía yo que Git almacena los archivos de manera comprimida y los nombra usando su hash (en función de SHA1) para evitar desperdicio de espacio en disco. Al igual que los archivos, los commits también se almacenan de esa manera.
Yo recordaba haber visto los archivos antes, pero no resultó ser con zcat
como creía. @dualbus acertadamente comentó que es un archivo comprimido con zlib y no con gzip. A pesar de que intentó ayudar y —en el momento— conseguir una herramienta para ver el contenido de un objeto (fuera blob, árbol o commit), tampoco lo encontró y opté por dejarlo pendiente.
Al final, resulta que Git mismo cuenta con una herramienta (de plomería, ¿recuerdan?) para desplegar el contenido de un objeto:
git cat-file -p
Ahora sí. Esto es lo que contiene un commit:
$ git cat-file -p 27a85581 tree e184b1069e064810284bdaeccf869864eb26d4b2 author Octavio Alvarez <alvarezp@alvarezp.ods.org> 1360986292 -0800 committer Octavio Alvarez <alvarezp@alvarezp.ods.org> 1360986292 -0800 Commit inicial. El programa corre correctamente.
El commit dice que su árbol está definido en el objeto e184b106. Veamos qué es lo que contiene este objeto:
$ git cat-file -p e184b106 100644 blob 05ac3eee8950be0a824ac88b9941cf88e950f345 README 100755 blob 603e950a96210e93a284237905e97dc72296b785 echoerr-func.bash 100755 blob 60c48ab8594d4b39c92e29cc886f744971fbf803 echoerr.bash
Y, bien, un blob consistiría simplemente de su contenido original; por ejemplo, para echoerr-func.bash, esto es lo que contiene el objeto 603e950a:
$ git cat-file -p 603e950a function echoerr() { echo $* > /dev/stderr }
Para ejemplificar un segundo commit, se corrigió un bug en el código. Se insertaron unas comillas que faltaban en echoerr.bash. En ningún momento se modificó echoerr-func.bash. Comparemos los árboles de los dos commits:
$ git cat-file -p 5ff92c11 tree 937cef46d4fba14cc7a07f039c875796fc31e9bf parent 27a8558158b6ddb033c649e4c49cb4e548850ec5 author Octavio Alvarez <alvarezp@alvarezp.ods.org> 1360986759 -0800 committer Octavio Alvarez <alvarezp@alvarezp.ods.org> 1360986759 -0800 Faltaba entrecomillar parametros de comparación. Se encontró que cuando se ejecutaba el programa sin argumentos, mostraba un error "unary operator". Creímos que corria bien, pero no. $ git cat-file -p 937cef46 100644 blob 05ac3eee8950be0a824ac88b9941cf88e950f345 README 100755 blob 603e950a96210e93a284237905e97dc72296b785 echoerr-func.bash 100755 blob 3ffd7dc8d2baedac1f9cad93231dc178e94e0c74 echoerr.bash
Ambos árboles hacen referencia al mismo archivo para echoerr-func.bash: 603e950a. De la misma forma para README ambos hacen referencia a 05ac3eee. Sin embargo, para echoerr.bash cada árbol hace referencia a un objeto distinto su propia versión del objeto.
Este es uno de los motivos por los que Git calcular un diff tan rápido. Ni siquiera necesita abrir los objetos para determinar si son diferentes. Sólo si el hash no coincide es que procede a mostrar el diff correspondiente.
Muchas gracias a todos los asistentes a la reunión. Nos vemos en la de marzo.
Oh! Yo pensé que no se valía usar el mismo git para decodificar el objeto. Es que sí venían dos soluciones usando git en la referencia de stackoverflow: http://stackoverflow.com/questions/3178566/deflate-command-line-tool