Git कम्प्यूट फ़ाइल हैश कैसे करता है?


124

पेड़ की वस्तुओं में संग्रहीत SHA1 हैश (जैसा कि लौटा दिया गया git ls-tree) फ़ाइल सामग्री के SHA1 हैश से मेल नहीं खाता (जैसा कि लौटा sha1sum)

$ git cat-file blob 4716ca912495c805b94a88ef6dc3fb4aff46bf3c | sha1sum
de20247992af0f949ae8df4fa9a37e4a03d7063e  -

Git कम्प्यूट फ़ाइल हैश कैसे करता है? क्या यह हैश की गणना करने से पहले सामग्री को संपीड़ित करता है?



1
अधिक जानकारी के लिए, progit.org/book/ch9-2.html
netvope

5
netvope की लिंक अब मृत प्रतीत होती है। मुझे लगता है कि यह नया स्थान है: git-scm.com/book/en/Git-Internals-Git-Objects जो -9.2 git-scm.com/book
Rhubbarb

जवाबों:


122

Git ऑब्जेक्ट को "बूँद" के साथ उपसर्ग करता है, उसके बाद लंबाई (मानव पठनीय पूर्णांक के रूप में), उसके बाद NUL वर्ण

$ echo -e 'blob 14\0Hello, World!' | shasum 8ab686eafeb1f44702738c8b0f24f2567c36da6d

स्रोत: http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html


2
यह भी ध्यान देने योग्य है कि यह "\ r \ n" को "\ n" से बदल देता है, लेकिन पृथक \ "r" को अकेला छोड़ देता है।
user420667

8
^ ऊपर टिप्पणी करने के लिए सुधार: कभी-कभी git ऊपर प्रतिस्थापन करता है, जो किसी की eol / autocrlf सेटिंग्स पर निर्भर करता है।
user420667

5
आप इसकी तुलना आउटपुट से भी कर सकते हैं echo 'Hello, World!' | git hash-object --stdin। वैकल्पिक रूप से आप --no-filtersयह सुनिश्चित करने के लिए निर्दिष्ट कर सकते हैं कि कोई भी शेल्फ रूपांतरण नहीं होता है, या इसके द्वारा निर्दिष्ट --path=somethi.ngफ़िल्टर का उपयोग करने के लिए निर्दिष्ट करें gitattributes(साथ ही @ user420620)। और -wवास्तव में करने के लिए ब्लॉब प्रस्तुत करने के लिए .git/objects(यदि आप कर रहे हैं एक Git रेपो में)।
टोबियास किंजलर

समतुल्यता व्यक्त करना, समझ बनाने के लिए: echo -e 'blob 16\0Hello, \r\nWorld!' | shasum == echo -e 'Hello, \r\nWorld!' | git hash-object --stdin --no-filters और यह भी \n१५ और १५ के बराबर होगा ।
पीटर क्रूस

1
echoआउटपुट के लिए एक नई लाइन जोड़ता है, जिसे गिट में भी पारित किया जाता है। इसीलिए इसके 14 अक्षर हैं। एक नई पंक्ति के बिना प्रतिध्वनि का उपयोग करने के लिए, लिखिएecho -n 'Hello, World!'
बुके वेरस्टीग

36

मैं केवल इस उत्तर पर विस्तार कर रहा हूं @Leif Gruenwoldtऔर इसके द्वारा प्रदान किए गए संदर्भ में विस्तार कर रहा हूं@Leif Gruenwoldt

यह स्वयं करो..

  • चरण 1. अपनी रिपॉजिटरी में एक खाली टेक्स्ट डॉक्यूमेंट (नाम से कोई फर्क नहीं पड़ता) बनाएं
  • चरण 2. दस्तावेज़ को चरणबद्ध और प्रतिबद्ध करें
  • चरण 3. निष्पादित करके बूँद के हैश की पहचान करें git ls-tree HEAD
  • चरण 4. बूँद के हैश का पता लगाएं e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
  • चरण 5. अपने आश्चर्य से बाहर स्नैप करें और नीचे पढ़ें

जीआईटी अपने प्रतिबद्ध हैश की गणना कैसे करता है

    Commit Hash (SHA1) = SHA1("blob " + <size_of_file> + "\0" + <contents_of_file>)

पाठ blob⎵एक निरंतर उपसर्ग है और \0निरंतर भी है और NULLचरित्र है। <size_of_file>और <contents_of_file>फ़ाइल के आधार पर बदलती।

देखें: फ़ाइल कमिट वस्तु का प्रारूप क्या है?

और सभी लोगों को thats!

लेकिन रुकें! क्या आपने देखा कि <filename>हैश गणना के लिए उपयोग किया जाने वाला पैरामीटर नहीं है? दो फाइलें संभावित रूप से एक ही हैश हो सकती हैं यदि उनकी सामग्री उसी तिथि और समय के प्रति उदासीन हैं जो उन्होंने बनाई थी और उनका नाम। यह उन कारणों में से एक है जो अन्य संस्करण नियंत्रण प्रणालियों की तुलना में Git हैंडल को स्थानांतरित करता है और बेहतर बनाता है।

यह अपने आप करो (एक्सटेंशन)

  • चरण 6. एक filenameही निर्देशिका में एक अलग के साथ एक और खाली फ़ाइल बनाएं
  • चरण 7. अपनी दोनों फाइलों के हैश की तुलना करें।

ध्यान दें:

लिंक में यह उल्लेख नहीं किया गया है कि treeऑब्जेक्ट कैसे हैशेड है। मैं एल्गोरिथ्म और मापदंडों के बारे में निश्चित नहीं हूं, लेकिन मेरे अवलोकन से शायद यह सभी ( blobsऔर treesउनके हैश) के आधार पर एक हैश की गणना करता है।


SHA1("blob" + <size_of_file>- बूँद और आकार के बीच अतिरिक्त स्थान चरित्र है? आकार दशमलव है? क्या यह शून्य-उपसर्ग है?
ऑग्सएक्स

1
@osgx है। संदर्भ और मेरा परीक्षण इसकी पुष्टि करता है। मैंने जवाब सही दिया है। आकार बिना किसी उपसर्ग के पूर्णांक के रूप में बाइट्स की संख्या प्रतीत होता है।
सैमुअल हरमर

13

git hash-object

यह आपकी परीक्षा पद्धति को सत्यापित करने का एक त्वरित तरीका है:

s='abc'
printf "$s" | git hash-object --stdin
printf "blob $(printf "$s" | wc -c)\0$s" | sha1sum

आउटपुट:

f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f  -

जहां sha1sumGNU Coreutils में है।

फिर यह प्रत्येक ऑब्जेक्ट प्रकार के प्रारूप को समझने के लिए नीचे आता है। हमने पहले ही तुच्छ को कवर किया है blob, यहाँ अन्य हैं:


जैसा कि पिछले उत्तर में बताया गया है, लंबाई की गणना इस प्रकार की जानी चाहिए $(printf "\0$s" | wc -c)। जोड़ा गया खाली वर्ण नोट करें। यही है, अगर स्ट्रिंग 'abc' है, तो सामने वाले खाली चरित्र के साथ लंबाई 4 होगी, 3 नहीं। फिर sha1sum के साथ परिणाम git हैश-ऑब्जेक्ट से मेल खाते हैं।
माइकल एकोका

आप सही हैं वे मैच करते हैं। ऐसा लगता है कि यहां इको-ई के बजाय प्रिंटफ का उपयोग करने से थोड़ा सा दुष्प्रभाव होता है। जब आप स्ट्रिंग 'एबीसी' वाली फ़ाइल में git हैश-ऑब्जेक्ट लगाते हैं, तो आपको 8baef1b ... f903 मिलता है, जो आपको प्रिंटो के बजाय इको-ई का उपयोग करते समय मिलता है। बशर्ते कि इको-ई एक स्ट्रिंग के अंत में एक नई रेखा जोड़ता है ऐसा लगता है कि प्रिंटफ के साथ व्यवहार से मेल खाने के लिए आप ऐसा ही कर सकते हैं (यानी s = "$ s \ n")।
माइकल एकोका

3

Leif Gruenwoldt उत्तर के आधार पर , यहां एक शेल फ़ंक्शन है 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/ .*$//'
}

परीक्षा:

$ echo 'Hello, World!' > test.txt
$ git hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
$ git-hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d

3

मुझे पायथन 3 में कुछ यूनिट परीक्षणों के लिए इसकी आवश्यकता थी, इसलिए मैंने सोचा कि मैं इसे यहाँ छोड़ दूंगा।

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()

मैं \nहर जगह लाइन एंडिंग से चिपक जाता हूं, लेकिन कुछ परिस्थितियों में इस हैश की गणना करने से पहले Git आपकी लाइन एंडिंग भी बदल सकता है, इसलिए आपको .replace('\r\n', '\n')वहां भी आवश्यकता हो सकती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.