2016-02-16 4 views
7

Sto cercando di capire come git calcola l'hash dei ref.Come viene calcolato l'hash git?

$ git ls-remote https://github.com/git/git 

.... 
29932f3915935d773dc8d52c292cadd81c81071d refs/tags/v2.4.2 
9eabf5b536662000f79978c4d1b6e4eff5c8d785 refs/tags/v2.4.2^{} 
.... 

Clona il repository in locale. Controllare il refs/tags/v2.4.2^{} ref sha

$ git cat-file -p 9eabf5b536662000f79978c4d1b6e4eff5c8d785 

tree 655a20f99af32926cbf6d8fab092506ddd70e49c 
parent df08eb357dd7f432c3dcbe0ef4b3212a38b4aeff 
author Junio C Hamano <[email protected]> 1432673399 -0700 
committer Junio C Hamano <[email protected]> 1432673399 -0700 

Git 2.4.2 

Signed-off-by: Junio C Hamano <[email protected]> 

Copiare il contenuto non compresso in modo che possiamo hash. (AFAIK git utilizza la versione non compressa quando è hashing) SHA-1

git cat-file -p 9eabf5b536662000f79978c4d1b6e4eff5c8d785 > fi 

di lasciare che il contenuto utilizzando git di proprio comando hash

git hash-object fi 
3cf741bbdbcdeed65e5371912742e854a035e665 

Perché l'uscita non è [9e]abf5b536662000f79978c4d1b6e4eff5c8d785? Capisco i primi due caratteri (9e) è la lunghezza in esadecimale. Come dovrei hash il contenuto di fi in modo che io possa ottenere il ref git abf5b536662000f79978c4d1b6e4eff5c8d785?

+0

(1) 'git hash-object' sta aggiungendo file, non altri tipi di oggetti. Ovviamente il tipo viene aggiunto al contenuto dell'hash in qualche modo. E scommetto che 9e non è la lunghezza, l'intera linea è un hash come l'algoritmo sha1 lo restituisce. – max630

risposta

2

Come descritto in "How is git commit sha1 formed", la formula è:

(printf "<type> %s\0" $(git cat-file <type> <ref> | wc -c); git cat-file <type> <ref>)|sha1sum 

Nel caso del commit 9eabf5b536662000f79978c4d1b6e4eff5c8d785 (che è v2.4.2^{} e che fa riferimento a un albero):

(printf "commit %s\0" $(git cat-file commit 9eabf5b536662000f79978c4d1b6e4eff5c8d785 | wc -c); git cat-file commit 9eabf5b536662000f79978c4d1b6e4eff5c8d785)|sha1sum 

Ciò darà 9eabf5b536662000f79978c4d1b6e4eff5c8d785.

come sarebbe:

(printf "commit %s\0" $(git cat-file commit v2.4.2{} | wc -c); git cat-file commit v2.4.2{})|sha1sum 

(ancora 9eabf5b536662000f79978c4d1b6e4eff5c8d785)

Allo stesso modo, calcolando la SHA1 del tag v2.4.2 sarebbe:

(printf "tag %s\0" $(git cat-file tag v2.4.2 | wc -c); git cat-file tag v2.4.2)|sha1sum 

Questo darebbe 29932f3915935d773dc8d52c292cadd81c81071d.

+0

Non so perché, ma ho diversi dati $ '(printf "albero% s \ 0" $ (git cat-file dell'albero 9eabf5b536662000f79978c4d1b6e4eff5c8d785 | wc -c); git tiragraffi file 9eabf5b536662000f79978c4d1b6e4eff5c8d785) | sha1sum 655a20f99af32926cbf6d8fab092506ddd70e49c' –

+0

Hai commesso commit e albero: usa lo stesso tipo – VonC

+0

L'ho aggiornato ... (usando l'albero). –

4

C'è un po 'di confusione qui. Git usa diversi tipi di oggetti: blob, alberi e commit. Il seguente comando:

git cat-file -t <hash> 

Indica il tipo di oggetto per un dato hash. Quindi nel tuo esempio, l'hash 9eabf5b536662000f79978c4d1b6e4eff5c8d785 corrisponde a un oggetto commit.

Ora, come è capito da soli, l'esecuzione di questo:

git cat-file -p 9eabf5b536662000f79978c4d1b6e4eff5c8d785 

si riporta il contenuto dell'oggetto in base al tipo (in questo caso, un commit).

Ma, questo:

git hash-object fi 

... calcola l'hash per un blob il cui contenuto è il risultato del comando precedente (nel tuo esempio), ma potrebbe essere qualsiasi altra cosa (come "ciao mondo ! "). Qui prova questo:

echo "blob 277\0$(cat fi)" | shasum 

L'output è lo stesso del comando precedente. Questo è fondamentalmente il modo in cui Git hash un blob. Quindi, con l'hashing, stai generando un oggetto blob. Ma come abbiamo visto, 9eabf5b536662000f79978c4d1b6e4eff5c8d785 è un commit, non un blob. Quindi, non è possibile eseguire l'hash fi così com'è per ottenere lo stesso hash.

L'hash di un commit è basato su molte altre informazioni che lo rendono unico (come il committer, l'autore, la data, ecc.). Il seguente articolo ti dice esattamente quello che un commit hash è composto da:

The anatomy of a git commit

Così si potrebbe ottenere lo stesso hash, fornendo tutti i dati di cui l'articolo con gli esatti stessi valori di quelli utilizzati nell'originale commettere.

Questo potrebbe essere utile pure:

Git from the bottom up