मैंने अपना खुद का Git बनाया
(tonystr.net)- version control system की आंतरिक संरचना को समझने के लिए Git जैसा एक सिस्टम खुद इम्प्लीमेंट किया गया
- Git के SHA-1 और zlib की जगह SHA-256 hash और zstd compression का उपयोग किया गया, और repository को
.tvcdirectory structure में संगठित किया गया - यह Rust में लिखा गया है, और file hash·compression·commit·checkout फीचर्स को चरणबद्ध तरीके से इम्प्लीमेंट किया गया
- commit object में tree hash, parent commit, author, message शामिल हैं, और एक ही फ़ाइल का hash समान होने पर उसे दोबारा स्टोर नहीं किया जाता
- Git के content-addressed file store होने को सीधे अनुभव करते हुए, structured data format के महत्व पर ज़ोर दिया गया
hashing और compression का तरीका
- Git सभी objects को SHA-1 hash से पहचानता है, लेकिन इस प्रोजेक्ट में SHA-256 का उपयोग किया गया
- SHA-1 पुराना है और सुरक्षा की दृष्टि से कमज़ोर है, लेकिन इस प्रोजेक्ट में इसका उपयोग सिर्फ़ फ़ाइल सामग्री की पहचान के लिए था, इसलिए security महत्वपूर्ण नहीं थी
- Git के zlib की जगह Facebook की zstd compression library अपनाई गई
- zstd को अधिक efficient माना गया, और Git compatibility इस प्रोजेक्ट का लक्ष्य नहीं था
- प्रोजेक्ट का नाम “tvc (Tony’s Version Control)” है, और
.tvcतथा.tvcignoreफ़ाइलें Git की संबंधित संरचनाओं के रूप में उपयोग की गईं
इम्प्लीमेंटेशन के चरण
- इम्प्लीमेंटेशन का क्रम command arguments पढ़ना → ignore rules पढ़ना → file list दिखाना → hash और compression → tree·commit बनाना → HEAD management → commit checkout था
- यह Rust में लिखा गया है, और
lscommand.tvcignorerules लागू करके non-ignored files को recursively खोजता है और हर फ़ाइल का SHA-256 hash दिखाता है - zstd library का उपयोग करके file compression और decompression फीचर को सरल रूप से इम्प्लीमेंट किया गया
commit की संरचना
- commit object में निम्न जानकारी शामिल होती है
- object type (
commit) - उस समय की file system state (tree hash)
- पिछला commit (HEAD)
- author
- commit message
- object type (
- Git के विपरीत author और committer के बीच का अंतर नहीं रखा गया, और merge या rebase जैसी सुविधाएँ इम्प्लीमेंट नहीं की गईं
- commit बनाते समय tree object बनाया, hash किया, compress किया और
.tvc/objects/में स्टोर किया जाता है, फिर HEAD फ़ाइल अपडेट की जाती है - समान hash वाली एक ही फ़ाइल को दोबारा स्टोर नहीं किया जाता, जिससे duplicate storage रोकना संभव होता है
tree object और checkout
generate_tree()function directories को traverse करते हुए हर फ़ाइल को hash, compress और store करता है, और filename तथा hash को string के रूप में व्यवस्थित करता है- subdirectories को recursive तरीके से प्रोसेस करके tree structure बनाया जाता है
- commit और tree objects को structs (
Commit,Tree) के रूप में parse किया गया ताकि उन्हें memory में आसानी से संभाला जा सके generate_fs()function tree structure के आधार पर file system को फिर से बनाता है और दिए गए path पर checkout करता है
प्रोजेक्ट से मिली सीख
- Git वास्तव में एक content-addressed (key-value) file store है, इसे सीधे अनुभव किया गया
- सबसे कठिन हिस्सा object format parsing था, और अगली बार YAML या JSON जैसे अधिक स्पष्ट format का उपयोग करने की योजना है
- पूरा कोड GitHub repository(tonystr/t-version-control) में प्रकाशित है
1 टिप्पणियां
Hacker News की राय
यह दिलचस्प है कि Git ही एकमात्र SCM है जो recursive merge strategy को सपोर्ट करता है
यह तरीका पुराने conflict resolution के इतिहास को अपने-आप याद रखता है, इसलिए बहुत उपयोगी है
बहुत से लोग अब भी rebase को पसंद करते हैं, लेकिन merge implement करते समय conflict resolution history store करने का mechanism ज़रूर होना चाहिए
संबंधित संदर्भ: Merge made by recursive strategy
संदर्भ: Git Tools - Rerere
लिंक
git mergeमें “null” strategy नहीं हैजब conflict पहले ही resolve हो चुका हो और सिर्फ merge का रिकॉर्ड छोड़ना हो, तब भी Git बेवजह मदद करने की कोशिश करता है
अच्छा होता अगर ऐसा कोई option होता जो index या worktree को छुए बिना सिर्फ merge होने का रिकॉर्ड कर देता
उदाहरण के लिए Pijul ऐसा करता है
इससे कई commits में हुई कोशिशें दिखती नहीं हैं, revert करना कठिन हो जाता है, और जो branch पहले ही merge हो चुकी हो उस पर आगे काम जारी रखना भी मुश्किल हो जाता है
जब कई PR एक ही puzzle के हिस्से हों, तो मुझे simple merge कहीं बेहतर लगता है
रोज़ इस्तेमाल होने वाले टूल्स के अंदरूनी हिस्से सीखना हमेशा मज़ेदार होता है
खासकर Git from the Bottom Up Git की internal structure को बहुत साफ़ तरीके से समझाने वाला शानदार लेख है
लगभग 20 मिनट में Git commands के अस्पष्ट काम करने के तरीके को समझा जा सकता है
cat-filecommand से hash ID को सीधे देखा जा सकता है, और यह काफ़ी बढ़िया हैअगर आप जानना चाहते हैं कि coding agents कैसे planning करते हैं, तो ऐसी पोस्टें ही उनके training data हैं
हालाँकि अगर लेखक ने LLM की मदद ली हो, तो यह एक तरह की circular situation भी बन सकती है
शायद public repositories को scrape करने वाले bots मौजूद हैं
यह सोचना अजीब लगता है कि मेरा code LLM training में इस्तेमाल हो सकता है
पोस्ट में खुद कोई LLM output नहीं है, लेकिन Rust code conventions या algorithm comparison पर सलाह लेने के लिए मैंने ChatGPT का इस्तेमाल किया था
CodeCrafters का “Build your own Git” tutorial वाकई शानदार है
Rust में इसे खुद implement करने वाली Jon Gjengset की live video भी recommend की जाती है
मैं भी चाहता हूँ कि version control का इस्तेमाल software के बाहर के क्षेत्रों में और ज़्यादा हो
GotVC E2E encryption, parallel import, और large file support architecture वाला एक दिलचस्प project है
आखिरकार उन्हें original program में खोलकर compare करना पड़ता है
यह पोस्ट देखकर ugit: DIY Git in Python याद आ गया
Git internals में गहराई तक जाते हुए भी आसानी से follow कराया गया यह सबसे बेहतरीन संसाधनों में से एक है
Meta के Mercurial fork Sapling VCS में Zstd dictionary compression का इस्तेमाल होता है
व्याख्यात्मक दस्तावेज़ में इसकी तुलना Git के delta-compressed packfile से की जा सकती है
छोटे repositories में Git का delta compression ज़्यादा efficient है, लेकिन बड़े repositories में path-based dictionary compression बेहतर है
हाल ही में Git में भी ऐसा ही “path-walk” feature जोड़ा गया है
मैंने भी ऐसा ही एक प्रयास किया था, और मेरे project का नाम “shit” है
GitHub लिंक
पहले मैंने एक SPA framework बनाने की कोशिश की थी और उसकी छिपी हुई जटिलता देखकर चौंक गया था
लगता है React या Angular developers भी ऐसे rabbit hole से गुज़रे होंगे
Git भी इसी तरह अपनी complexity को बहुत अच्छे से छिपाता है
मैंने PHP में लिखा एक Git client देखा था, जो packfile और reftable पढ़ सकता है और LCS-based diff भी support करता है
gipht-horse
और यह भी पहली बार पता चला कि
@को HEAD की जगह इस्तेमाल किया जा सकता है, जो syntax के हिसाब से काफ़ी तार्किक है