tipos - ¿Cómo calcula git hashes de archivos?
subir archivos git (5)
Git prefija el objeto con "blob", seguido de la longitud (como un entero legible por el ser humano), seguido de un carácter NUL
$ echo -e ''blob 14/0Hello, World!'' | shasum 8ab686eafeb1f44702738c8b0f24f2567c36da6d
Fuente: http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html
Los valores hash SHA1 almacenados en los objetos del árbol (como los devuelve git ls-tree
) no coinciden con los valores hash SHA1 del contenido del archivo (tal como lo devuelve sha1sum
)
$ git cat-file blob 4716ca912495c805b94a88ef6dc3fb4aff46bf3c | sha1sum
de20247992af0f949ae8df4fa9a37e4a03d7063e -
¿Cómo calcula git hashes de archivos? ¿Comprime el contenido antes de calcular el hash?
Lo necesitaba para algunas pruebas unitarias en Python 3, así que pensé que lo dejaría aquí.
def git_blob_hash(data):
if isinstance(data, str):
data = data.encode()
data = b''blob '' + str(len(data)).encode() + b''/0'' + data
h = hashlib.sha1()
h.update(data)
return h.hexdigest()
Me adhiero a /n
terminaciones de línea en todas partes, pero en algunas circunstancias Git también podría estar cambiando las terminaciones de línea antes de calcular este hash, así que es posible que necesites un .replace(''/r/n'', ''/n'')
allí también.
Según la respuesta de , aquí hay una función de shell que sustituye a git hash-object
:
git-hash-object () { # substitute when the `git` command is not available
local type=blob
[ "$1" = "-t" ] && shift && type=$1 && shift
# depending on eol/autocrlf settings, you may want to substitute CRLFs by LFs
# by using `perl -pe ''s//r$//g''` instead of `cat` in the next 2 commands
local size=$(cat $1 | wc -c | sed ''s/ .*$//'')
( echo -en "$type $size/0"; cat "$1" ) | sha1sum | sed ''s/ .*$//''
}
Prueba:
$ echo ''Hello, World!'' > test.txt
$ git hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
$ git-hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
Solo estoy ampliando la respuesta de @Leif Gruenwoldt
y detallando lo que está en la http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html proporcionada por @Leif Gruenwoldt
Hazlo tu mismo..
- Paso 1. Crea un documento de texto vacío (el nombre no importa) en tu repositorio
- Paso 2. Etapa y compromiso del documento
- Paso 3. Identifica el hash del blob ejecutando
git ls-tree HEAD
- Paso 4. Encuentra el hash del blob para ser
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
- Paso 5. Salga de su sorpresa y lea a continuación
¿Cómo calcula GIT sus hashes de confirmación?
Commit Hash (SHA1) = SHA1("blob " + <size_of_file> + "/0" + <contents_of_file>)
El texto blob⎵
es un prefijo constante y /0
también es constante y es el carácter NULL
. El <size_of_file>
y <contents_of_file>
varían según el archivo.
¡Y eso es todo amigos!
¡Pero espera! , ¿notó que el <filename>
no es un parámetro utilizado para el cálculo hash? Dos archivos podrían tener el mismo hash si sus contenidos son indiferentes a la fecha y hora en que fueron creados y su nombre. Esta es una de las razones por las que Git maneja movimientos y cambia el nombre mejor que otros sistemas de control de versiones.
Hágalo usted mismo (Ext)
- Paso 6. Crea otro archivo vacío con un
filename
defilename
diferente en el mismo directorio- Paso 7. Compara los hashes de tus dos archivos.
Nota:
El enlace no menciona cómo se codifica el objeto del tree
. Sin embargo, no estoy seguro del algoritmo y los parámetros de mi observación. Probablemente computa un hash basado en todos los blobs
y trees
(probablemente sus hashes) que contiene
git hash-object
es una forma rápida de verificar tu método de prueba:
s=''abc''
printf "$s" | git hash-object --stdin
printf "blob $(printf "$s" | wc -c)/0$s" | sha1sum
Salida:
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f -
donde sha1sum
está en GNU Coreutils.