जब Git टूटता है: रोज़ 30,000 मर्ज वाले मोनोरेपो के सबक
उच्च मर्ज दर पर Git मोनोरेपो स्केलिंग अनुमानित तरीकों से क्यों टूटता है। always-online क्लाइंट और सर्वर-साइड कमिट से मिले सबक।

अगर आप git मोनोरेपो चलाते हैं, तो भविष्य में कहीं न कहीं एक ऐसी संख्या आएगी जहाँ सब कुछ बिखरने लगता है। Anthropic के लिए वह संख्या लगभग रोज़ 30,000 मर्ज, 100 GB का main-branch इतिहास, और रोज़ लगभग 25 मिलियन CI checkouts थी। अगर इन्हें भोलेपन से fetch किया जाए, तो यह हर रोज़ 600 petabytes से ज़्यादा git traffic बनता है। उनका जवाब था पाँच महीनों में अपना खुद का version control system लिख देना। आपका जवाब ऐसा नहीं होना चाहिए। पर रास्ते में उन्होंने जो गलतियाँ कीं, वही गलतियाँ मैं इसके दसवें हिस्से के पैमाने वाली टीमों में भी देखता हूँ, तो चलिए उन्हें एक-एक करके समझते हैं।
गलती एक: केंद्रीकृत वर्कफ़्लो को वितरित वर्कफ़्लो की तरह चलाना
Git की मूल डिज़ाइन की शर्त विकेंद्रीकरण है। हर clone एक पूरा repository होता है: पूरा इतिहास, पूरा object store, और बिना नेटवर्क के भी पूरी तरह काम करने वाला। इसी शर्त ने git को दुनिया भर में स्थापित किया, और ज़्यादातर repos के लिए यह आज भी सही है। पर एक बात लगभग कोई स्वीकार नहीं करता: ज़्यादातर लोग git को असल में इस तरह इस्तेमाल ही नहीं करते। आपकी संस्था के पास GitHub या GitLab पर एक ही आधिकारिक remote होता है। डेवलपर लगातार push और pull करते हैं। आपके CI runners परिभाषा से ही online रहते हैं। यानी आप एक केंद्रीकृत system चला रहे हैं, बस वितरित system का चोला पहने हुए, और उसकी वितरित लागतें भी भर रहे हैं। हर CI job ऐसा इतिहास खींच रही है जिसे वह कभी पढ़ेगी नहीं, हर agent sandbox ऐसे packfiles बना रहा है जिनकी उसे ज़रूरत ही नहीं।
Anthropic के redesign का यह पहला असली सबक है। जब उन्होंने एक क़दम पीछे हटकर देखा, तो पाया कि उनके क्लाइंट “agents और jobs हैं जो परिभाषा से ही online रहते हैं।” इसलिए उन्होंने ऐसे server के इर्द-गिर्द डिज़ाइन किया जो हमेशा पहुँच में हो। क्लाइंट जानबूझकर सीधा-सादा बनाया गया: एक सीमित local cache, disk पर एक working copy, और एक filesystem watcher। blame, diff और merge की गणना server करता है। यही निष्कर्ष Google ने Piper के साथ और Meta ने Sapling के साथ निकाला। यह git के खिलाफ़ कोई रुख नहीं है, बल्कि इस बात की पहचान है कि आर्किटेक्चर को असली workload के हिसाब से होना चाहिए, न कि उस workload के हिसाब से जिसके लिए टूल बीस साल पहले बना था। यह पैटर्न मैंने security tooling में भी देखा है: टीमें offline-capable agent architecture deploy करती हैं और फिर उसे ऐसे माहौल में चलाती हैं जहाँ offline कभी होता ही नहीं, और फिर हैरान होती हैं कि उनकी sync layer इतनी बुरी क्यों है।
आपकी टीम के लिए इसका सबक “एक VCS बनाओ” नहीं है। सबक है: अपनी मान्यताओं का ऑडिट करो। लिखो कि git की कौन-सी खूबियों पर तुम असल में निर्भर हो। Offline काम? असली forks? Cryptographic commit signing? अगर ईमानदार जवाब है “एक remote, हमेशा online, CI ही सब कुछ करता है,” तो उस वितरित workflow को optimize करना बंद करो जो तुम्हारे पास है ही नहीं, और checkout व query की लागत को optimize करना शुरू करो।
गलती दो: mirrors और seeds से scale को ढकना
हर बड़ी repo वाली टीम एक ही दुख के चरणों से गुज़रती है। पहले shallow clones, फिर sparse checkouts और promisor remotes। फिर internal git mirrors, फिर blob storage में snapshot “seeds” ताकि CI jobs tip-of-main के आसपास की किसी चीज़ से शुरू कर सकें। Anthropic ने ये सब आज़माए। चरम पर उनके पास कई सौ internal mirrors थे। और असफलता का तरीका हमेशा एक जैसा होता है: ये workarounds ज़ोर से फेल नहीं होते, ये धीरे-धीरे सड़ते हैं। Seeds refresh के बीच tip से और दूर खिसकते जाते हैं। Partial clones git blame और git log --follow को उलझाने वाले तरीकों से तोड़ देते हैं। किसी का bisect चुपचाप गलत नतीजे देने लगता है, क्योंकि इतिहास कटा हुआ है। यह तब तक किसी को पता नहीं चलता जब तक incident review न हो।
आखिरी वाली बात मुझे रात को जगाए रखती है। इतिहास की partial correctness वाले bugs ठीक उसी तरह के सूक्ष्म गलत व्यवहार हैं जो उस अंतर में रहते हैं जो आपको लगता है कि system गारंटी देता है, और जो वह असल में करता है। Shallow clone तब error नहीं देता जब आप उसकी गहराई से आगे का blame माँगते हैं; वह बस अधूरा जवाब दे देता है। अगर आपकी automated revert pipeline उस जवाब पर भरोसा करती है, तो आपने एक ऐसी मशीन बना ली है जो आत्मविश्वास से गलत change को revert कर देती है।
- Shallow clones इतिहास पर निर्भर tooling (blame, bisect, merge-base) को चुपचाप तोड़ देते हैं, ज़ोर से नहीं।
- Snapshot seeds tip-of-main से दूर होते जाते हैं; merge rate जितनी ज़्यादा होगी, drift उतनी तेज़ होगी, यानी load बढ़ते ही workaround सबसे ज़्यादा बिगड़ता है।
- Mirror fleets operational surface बढ़ाते हैं: सैकड़ों stateful copies जो अलग-अलग पीछे रह सकती हैं, corrupt हो सकती हैं, या disk से बाहर जा सकती हैं।
- इतिहास के अर्थ को छूने वाले हर workaround को regression test चाहिए, वरना incident के दौरान वह आप पर ही भारी पड़ेगा।
Anthropic के पैमाने पर समाधान संरचनात्मक था: repo की कोई पूरी तरह materialized copy कहीं भी नहीं है, server पर भी नहीं, और सब कुछ content-addressed और horizontally cacheable है। आपके पैमाने पर समाधान अधिक साधारण है: गिनो कि कितनी मशीनों में पूरी या लगभग पूरी repo कॉपी है, और हर एक के drift और failure modes के बारे में ईमानदार रहो।
गलती तीन: हर CI job का अपना repo copy रखना
अपने CI fleet के बारे में एक सवाल पूछने लायक है: उन jobs में से कितनों को सच में working copy चाहिए? Anthropic का जवाब, अपना system बनाने के बाद, था “हमारी अपेक्षा से बहुत कम।” जिस job को किसी commit और उसके merge base के बीच का diff चाहिए, या किसी file का blame, या किसी path को छूने वाले commits की सूची, वह API के ज़रिए सीधे server से पूछ सकती है। न clone, न fetch, न disk। उनकी automated bisect और revert pipelines उस सस्ती programmatic पहुँच के बिना “बड़े पैमाने पर व्यावहारिक नहीं” होतीं। और मैं इस पर भरोसा करता हूँ, क्योंकि मैंने टीमों को वही pipelines local clones के ऊपर चलाने की कोशिश करते और fetch के समय में डूबते देखा है।
यह सिद्धांत source control से कहीं आगे तक लागू होता है। Checkout को महँगा अपवाद समझो, डिफ़ॉल्ट नहीं। जब किसी job को सच में फ़ाइलें चाहिए, तो sparse और virtualized checkouts, जो सिर्फ़ माँगी गई directories या असल में पढ़ी गई फ़ाइलों को materialize करते हैं, लागत को कई गुना घटा देते हैं। Anthropic का fetch protocol git की negotiation को पूरी तरह हटा देता है: क्लाइंट विशिष्ट immutable trees और blobs माँगता है, कोई भी cache जवाब दे सकता है, और पूरा सिस्टम एक tiered CDN की तरह चलता है, न कि एक smart server की तरह जो हर क्लाइंट के लिए packfile की गणना करता है। अगर आपने कभी CI लोड में git server को पिघलते हुए profile किया है, तो आप समझेंगे कि यह क्यों मायने रखता है: packfile बनाना CPU-भारी होता है, क्योंकि protocol server से कहता है कि हर क्लाइंट के पास पहले से मौजूद चीज़ के मुकाबले delta की गणना करे।
अगर आपके क्लाइंट हमेशा online हैं और एक ही आधिकारिक कॉपी है, तो आपकी बनाए रखी हर local clone एक ऐसा cache है जिसकी आप पूरी कीमत चुका रहे हैं, और बदले में cache जैसी ही सुविधा पा रहे हैं।
गलती चार: कमिट की लागत को repo के आकार के साथ बढ़ने देना
उनके डिज़ाइन का सबसे दिलचस्प इंजीनियरिंग फ़ैसला changeset है। git commit एक tree की ओर इशारा करता है जो पूरी repository की स्थिति दर्शाता है। उनका changeset सिर्फ़ उन फ़ाइलों की सूची दर्ज करता है जो अपने पहले parent के सापेक्ष बदली हैं, साथ में blob storage के content-addressed pointers, और यह सब एक write-ahead log में जुड़ता है। कोई packfiles स्वीकार नहीं करने होते, कोई locking नहीं, कोई cross-server coordination नहीं। Refs, यानी branches और tags, जानबूझकर पीछे रखे गए हैं, क्योंकि “वैश्विक state जिस पर हर server को सहमत होना पड़े, एक बड़ी scaling समस्या है।” Ref को आगे बढ़ाना एक एकल Spanner row पर compare-and-swap है, जो commit बनाने से अलग है।

इसका साथी विचार है “derived data”: blame indices, path history, commit-graph skip lists, ये सब हर changeset के parents से पुनरावर्ती तरीके से गणना होते हैं, और एक ही सामान्य तंत्र से चलते हैं। प्रकार के हिसाब से तय करो कि उसे तुरंत compute करना है या आलसी तरीके से। क्लाइंट को छुए बिना नए index types जोड़ सकते हो। यह event-sourced systems के लिए सच में अच्छा पैटर्न है। मैंने audit-log pipelines के लिए भी यही आकार सुझाया है, जहाँ append-only log ही सच है और हर query structure एक दोबारा बनाई जा सकने वाली projection है। जिस पल कोई इस तंत्र से बाहर projection हाथ से संभालने लगता है, drift तय है।
Security के नज़रिए से एक चेतावनी: केंद्रीकरण की चिंता करने वाले टिप्पणीकारों की बात गंभीरता से लेने लायक है। एक ही server-side system जहाँ कमिट, merges और इतिहास की सभी queries रहती हैं, वह एक बेहद मूल्यवान target है, और “सबको नियंत्रित करने वाली एक repo” पर लिखने की पहुँच वाले AI agents जोखिम को बुरी तरह केंद्रित कर देते हैं। Anthropic ने साथ में एक “rich source control IAM system” बनाया, और उसकी बारीकियाँ data structures से ज़्यादा मायने रखती हैं। अगर आप केंद्रीकरण करते हैं, तो आपका blast-radius हिसाब बदल जाता है: पहले दिन से isolation, per-agent credentials और audit का बजट रखो, तीसरे क्वार्टर तक का इंतज़ार मत करो। जो टीमें साझा infrastructure पर stateful agents चलाती हैं, उन्हें यह दर्द पहले से पता है।
गलती पाँच: यह मान लेना कि रोज़ 30,000 मर्ज का मतलब रोज़ 30,000 अच्छे फ़ैसले हैं
इंजीनियरिंग प्रभावशाली है। असली सवाल यह है कि उसके ज़रिए क्या बह रहा है। एक practitioner ने इसे सीधे शब्दों में कहा: जब भी वे AI-generated code की review छोड़ते हैं, तो “बाद में मुझे घटिया, गड़बड़ चीज़ें मिलती हैं। हर review में ऐसी गड़बड़ नहीं मिलती, पर इतनी बार मिलती है कि मैं सब कुछ review करना नहीं छोड़ सकता।” इस hit rate को 30,000 रोज़ के merges से गुणा करो, तो समझ आता है कि Anthropic को “reviewed code के बड़े पैमाने पर प्रबंधन और landing के नए तरीके” भी क्यों बनाने पड़े: review की सतह, landing queue, और automated revert pipelines। VCS उत्पाद नहीं था। landing pipeline उत्पाद था। Source control तभी bottleneck बना जब उससे पहले review की क्षमता bottleneck बन गई।
उनकी युद्ध-कथाओं में एक ईमानदार बात भी छिपी है: प्रोजेक्ट के इंजीनियरों ने अपनी ज़्यादातर भूमिका को coding agent से “नहीं” कहने के रूप में बताया। उनकी हाथ से लिखी prototype ingestion pipeline तब तक ठीक थी जब तक एक नए model ने उसे memory में 20 गुना हल्का और 4 गुना तेज़ नहीं लिख दिया। पर वहाँ तक पहुँचने के लिए ऐसे इंसान चाहिए थे जिनकी परख हो कि क्या स्वीकार करना है। यह मैंने जो भी देखा है उससे मेल खाता है: AI इंजीनियर का काम लिखने से हटाकर review की ओर ले जाता है, और अब review की throughput ही दुर्लभ संसाधन है। हमने पहले लिखा है कि review की हर परत टीम को धीमा करती है। मुश्किल यह है कि agent-generated code के साथ review की परतें हटाना भी सुरक्षित नहीं है। तुम्हें कम review नहीं, बेहतर review tooling चाहिए।
असल में आपको क्या करना चाहिए
आप Anthropic नहीं हैं। आपके पास उनका token budget नहीं है, जैसा वे खुद मानते हैं, और रोज़ 25 मिलियन checkouts भी नहीं हैं। पर AI coding tools सबके merge rates बढ़ा रहे हैं, और दबाव के बिंदु एक अनुमानित क्रम में आते हैं। मैं यह क्रम अपनाऊँगा, जिसे मैं Priya का कम-पछतावे वाला नियम कहता हूँ:
- पहले मापो। रोज़ के checkouts, हर CI job में fetch हुए bytes, और कितनी मशीनों में पूरी repo कॉपी है, गिनो। Scale की समस्या से पहले शायद आपकी बर्बादी की समस्या है।
- अनावश्यक checkouts बंद करो। Metadata के सवाल (diffs, blame, ancestry) APIs पर ले जाओ, GitHub/GitLab APIs या एक पतली internal service, इससे पहले कि आप कोई infrastructure खरीदो।
- Sparse और partial clones को सुरक्षित बनाओ। अपने bisect, blame और revert tooling को shallow clones पर स्पष्ट रूप से टेस्ट करो, या automation में उन पर रोक लगा दो।
- जहाँ संभव हो, CI को server-side, immutable-object fetches पर डिफ़ॉल्ट करो, और mirror fleets को ऐसा तकनीकी कर्ज़ मानो जिस पर ब्याज चक्रवृद्धि से बढ़ता है।
- Repo format के बजाय landing pipeline में निवेश करो। Review क्षमता, merge queues और automated revert वहीं हैं जहाँ agent-scale development सबसे पहले टूटता है।
- उसके बाद ही वैकल्पिक VCS architectures पर विचार करो जैसे Sapling, जो open source है और खुद लिखे बिना client-server के ज़्यादातर फ़ायदे देता है।
इस पूरी सीख का सबसे गहरा पहलू git के बारे में है ही नहीं। हर टूल अपने workload की मान्यताएँ अपने भीतर रखता है: offline इंसान, एक समय में एक commit, और ऐसा code जो review से तेज़ लिखा जाए। ये मान्यताएँ अभी agents तोड़ रहे हैं, infrastructure में, review में, और security की सीमाओं पर। जो टीमें आगे निकलेंगी, वे सब कुछ शून्य से दोबारा नहीं बनाएँगी। वे वही होंगी जिन्होंने पहचाना कि कौन-सी मान्यता पहले टूटी, और ठीक उसी को ठीक किया।


