Git tree hash id generación

Al principio, inicialice un repository que contenga un file llamado rose

$: echo sweet > rose $: git init $: git add . $: find .git/objects/ -type f .git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d $: git commit -m "rose" $: find .git/objects/ -type f -printf "%h%f %s\n" .git/objects/05b217bb859794d08bb9e4f7f04cbda4b207fbe9 49 .git/objects/aa823728ea7d592acc69b36875a482cdf3fd5c8d 21 .git/objects/665d02ccbacdde1c0f2eecde01fbf47144ddd492 124 

Entonces quiero sha el blob y ver cómo generar el id del tree-object

 echo -e "tree 21\0100644 rose\0aa823728ea7d592acc69b36875a482cdf3fd5c8d"|sha1sum 

Lo que imprime no es 05b217bb859794d08bb9e4f7f04cbda4b207fbe9
¿Dónde estoy equivocado?

echo inserta una línea nueva de forma pnetworkingeterminada, a less que especifique el indicador -n (omitir línea nueva).

Además, la ID de blob no se almacena en formatting ASCII, sino como valor binary. Esto da como resultado un tamaño de object de 32 (no 21).

El siguiente command le dará el resultado correcto:

 echo -en 'tree 32\x00100644 rose\x00\xaa\x82\x37\x28\xea\x7d\x59\x2a\xcc\x69\xb3\x68\x75\xa4\x82\xcd\xf3\xfd\x5c\x8d' | sha1sum 

El ID del object en el tree no está almacenado en ese formatting. Echar un vistazo:

 git cat-file tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | od -c 

Más bien, los datos del tree son una secuencia de <mode> SP <filename> NUL <hash> , donde <mode> es el <mode> forma de cadena, y <hash> es el SHA1 de 20 octetos.

El formatting de un object de tree es el siguiente:

 tree SIZE\0ENTRIES 

SIZE es el tamaño del tree.
ENTRIES es una secuencia donde cada elemento representa un object referencedo por el tree.
Cada input de object está formateada de la siguiente manera:

 MODE NAME\0BSHA 

MODE es:

  • 100644 para un file normal,
  • 100755 para un file ejecutable,
  • 120000 para un enlace simbólico,
  • 040000 para un object de tree.

NAME es el directory o nombre de file.
BSHA es una representación binaria de la ID del object.

Con respecto al ejemplo del OP, consigamos una reference al tree superior (twig principal):

 $ git write-tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 

Si bien usaré este tree-ish, lo que sigue se aplica a cada tree.
Los primeros 6 caracteres ( 05b217 ) son suficientes.

El contenido del tree en formatting legible para humanos viene dado por:

 $ git ls-tree 05b217 100644 blob aa823728ea7d592acc69b36875a482cdf3fd5c8d rose 

Puede replace git ls-tree con git cat-file -p .

El formatting binary es similar al dado por:

 $ git cat-file tree 05b217 100644 rose ▒▒7(▒}Y*▒i▒hu▒▒▒▒▒\▒% 

El contenido real también tiene el tree [content size]\0 cadenas inicial tree [content size]\0 .
Para getlo, puede descomprimir el file que almacena el tree dentro de la carpeta .git , utilizando el formatting de hash 2/38:

 $ openssl zlib -d -in .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 tree 32 100644 rose ▒▒7(▒}Y*▒i▒hu▒▒▒▒▒\▒% 

Dados los objects almacenados en el tree y disponibles a través de ls-tree , uno podría generar el contenido (real) almacenado con un script awk:

 $ git ls-tree 05b217 | awk -b 'function bsha(asha)\ {patsplit(asha, x, /../); h=""; for(j in x) h=h sprintf("%c", strtonum("0x" x[j])); return(h)}\ {t=t sprintf("%d %s\0%s", $1, $4, bsha($3))} END {printf("tree %s\0%s", length(t), t)}' tree 32 100644 rose ▒▒7(▒}Y*▒i▒hu▒▒▒▒▒\▒% 

Para comprender mejor el resultado, produzco una versión del mismo usando secuencias de escape:

 $ git ls-tree 05b217 | awk -b 'function bsha(asha)\ {patsplit(asha, x, /../); h=""; for(j in x) h=h sprintf("%s", "\\x" x[j]); return(h)}\ {t=t sprintf("%d %s\0%s", $1, $4, bsha($3))} END {printf("tree %s\0%s", length(t), t)}' tree 92 100644 rose \xaa\x82\x37\x28\xea\x7d\x59\x2a\xcc\x69\xb3\x68\x75\xa4\x82\xcd\xf3\xfd\x5c\x8d% 

Compare esta salida con la salida anterior de git ls-tree 05b217 .

Ahora vengo a la generación de hash de tree usando diferentes methods.

Usando la versión almacenada de file del tree:

 $ openssl zlib -d -in .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | shasum 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 *- 

Usando mi contenido generado por awk:

 $ git ls-tree 05b217 | awk -b 'function bsha(asha)\ {patsplit(asha, x, /../); h=""; for(j in x) h=h sprintf("%c", strtonum("0x" x[j])); return(h)}\ {t=t sprintf("%d %s\0%s", $1, $4, bsha($3))} END {printf("tree %s\0%s", length(t), t)}' | shasum 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 *- 

Y finalmente el command git mktree :

 # git ls-tree 05b217 | git mktree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 

El hash obtenido siempre es el mismo.