2016-06-09 8 views
6

मैं एक गिट कोर्स पर काम कर रहा हूं और उल्लेख करना चाहता हूं कि git gc चलाने तक खोए गए रेफरी वास्तव में खो नहीं गए हैं। लेकिन यह सत्यापित करते हुए, मुझे पता चला कि यह मामला नहीं है। git gc --prune=all --aggressive चलाने के बाद भी खोए गए रेफरी अभी भी वहां हैं।जब गिट प्रिंस ऑब्जेक्ट्स वास्तव में करता है: "गिट जीसी" क्यों नहीं निकलता है?

स्पष्ट रूप से मैंने कुछ गलत समझा। और पाठ्यक्रम में कुछ गलत कहने से पहले, मैं अपने तथ्यों को सीधे प्राप्त करना चाहता हूं!

#!/bin/bash 

git init 

# add 10 dummy commits 
for i in {1..10}; do 
    date > foo.txt 
    git add foo.txt 
    git commit -m "bump" foo.txt 
    sleep 1 
done; 

CURRENT=$(git rev-parse HEAD) 
echo HEAD before reset: ${CURRENT} 

# rewind 
git reset --hard HEAD~5 

# add another 10 commits 
for i in {1..10}; do 
    date > foo.txt 
    git add foo.txt 
    git commit -m "bump" foo.txt 
    sleep 1 
done; 

यह स्क्रिप्ट, 10 डमी करता जोड़ने अतीत में 5 प्रतिबद्ध करने के लिए रीसेट और एक अन्य 10 प्रतिबद्ध जोड़ देगा: यहाँ एक उदाहरण स्क्रिप्ट प्रभाव दिखाता है। रीसेट करने से ठीक पहले, यह इसके वर्तमान हेड के हैश को प्रिंट करेगा।

मैं git gc --prune=all चलाने के बाद CURRENT में वस्तु खोने के लिए उम्मीद करेंगे। फिर भी, मैं अभी भी हैश पर git show चला सकता हूं।

मुझे समझ में आता है कि git reset चलाने और नई प्रतिबद्धताओं को जोड़ने के बाद, मैंने अनिवार्य रूप से एक नई शाखा बनाई है। लेकिन मेरी मूल शाखा में अब कोई संदर्भ नहीं है, इसलिए यह git log --all में दिखाई नहीं देता है। मुझे लगता है कि किसी भी रिमोट पर भी धक्का नहीं दिया जाएगा।

git gc की मेरी समझ उन वस्तुओं को हटा दी गई थी। प्रतीत नहीं होता यही मामला होगा।

क्यों? और जब वास्तव में git gc वस्तुओं को हटाता है?

+2

आपके रीफ्लॉग में अभी भी "हटाए गए" काम करने के संदर्भ शामिल हैं। उन टाइमआउट तक या आप उन्हें स्पष्ट रूप से समाप्त कर देते हैं, वे छेड़छाड़ नहीं करेंगे। – twalberg

+0

दिलचस्प। मैंने https://git-scm.com/docs/git-reflog पर एक नज़र डाली है और 'git reflog --expire = all' चलाया है। जिसके बाद वस्तु * अभी भी * थी। इसके बाद मैंने एक और 'जीसी' चलाया और यह अभी भी वहां था। यहां तक ​​कि एक और 'git gc - आक्रामक --prune = all' मदद नहीं की। – exhuma

+0

आपको '--expire = all --all' की आवश्यकता है, या इसे 'HEAD' (डिफ़ॉल्ट) और' मास्टर' दोनों पर चलाने के लिए। या आप विशिष्ट प्रविष्टियों को मैन्युअल रूप से हटा सकते हैं (या नीचे उत्तर देखें)। – torek

उत्तर

10

किसी ऑब्जेक्ट को छीनने के लिए, इसे दो मानदंडों को पूरा करना होगा। एक तिथि/समय संबंधित है: यह संग्रह के लिए परिपक्व होने के लिए बहुत पहले बनाया गया था। "लंबे समय से पहले" भाग वह है जिसे आप --prune=all के साथ सेट कर रहे हैं: आप सामान्य "कम से कम दो सप्ताह पुरानी" सेटिंग को ओवरराइड कर रहे हैं।

दूसरा मानदंड वह जगह है जहां आपका प्रयोग गलत हो रहा है। छेड़छाड़ करने के लिए, ऑब्जेक्ट भीपहुंच योग्य होना चाहिए। twalberg noted in a comment के रूप में, गिट की "रीफ्लॉग" प्रविष्टियों के माध्यम से, आपके प्रत्येक स्पष्ट रूप से छोड़े गए काम (और इसलिए उनके संबंधित पेड़ और ब्लब्स) वास्तव में संदर्भित होते हैं।

ऐसे प्रत्येक के लिए दो reflog प्रविष्टियों रहे हैं प्रतिबद्ध: HEAD के लिए, और शाखा का नाम के लिए एक जो HEAD ही समय में refs/heads/master, यानी, शाखा master के लिए प्रतिबद्ध किया गया था (इस मामले में, reflog करने के लिए भेजा)। प्रत्येक रीफ्लॉग एंट्री का अपना टाइम-स्टैंप होता है, और git gc आपके लिए रीफ्लॉग प्रविष्टियों की भी समय सीमा समाप्त करता है, हालांकि ऑब्जेक्ट की समाप्ति के लिए सरल "14 दिनों" डिफ़ॉल्ट से नियमों के अधिक जटिल सेट के साथ।

इसलिए, git gc पहले हटा सकता है सभी reflog प्रविष्टियों को चारों ओर पुराने वस्तु रख रहे हैं, तो वस्तु छांटना। यह सिर्फ यहाँ नहीं हो रहा है।

मैन्युअल रूप से प्रविष्टियों को रीफ्लॉग करने या हटाने के लिए, git reflog का उपयोग करें।ध्यान दें कि git refloggit log-g/--walk-reflogs विकल्प (साथ ही कुछ अतिरिक्त प्रदर्शन स्वरूपण विकल्प) के साथ चलाकर प्रविष्टियां प्रदर्शित करता है। आप सब कुछ साफ़ करने के लिए git reflog --all --expire=all चला सकते हैं, हालांकि यह एक धुंधलापन है जब स्केलपेल अधिक उपयुक्त हो सकता है। थोड़ी अधिक चुनिंदाता के लिए --expire-unreachable का उपयोग करें। इसके बारे में अधिक जानकारी के लिए, the git log documentation और निश्चित रूप से the git reflog documentation देखें।


कुछ यूनिक्स-y फाइल सिस्टम की दुकान फ़ाइल निर्माण ("जन्म") समय बिल्कुल नहीं करते हैं: एक stat संरचना के st_ctime क्षेत्र inode परिवर्तन समय, नहीं निर्माण का समय है। यदि कोई सृजन समय है, तो यह st_birthtime या st_birthtimespec में है। हालांकि, प्रत्येक गिट ऑब्जेक्ट केवल पढ़ने के लिए है, इसलिए फ़ाइल का निर्माण समय भी इसके संशोधन का समय है। इसलिए st_mtime, जो हमेशा उपलब्ध है, वस्तु के लिए निर्माण समय देता है।

सटीक नियम the git gc documentation में वर्णित हैं, लेकिन मैं करता नहीं पहुंचा जा सकता प्रतिबद्ध के लिए डिफ़ॉल्ट रूप से, 30 दिन और पहुंच योग्य के लिए 90 दिनों के एक सभ्य सार है लगता है। पहुंचने योग्य की परिभाषा यहां असामान्य है, हालांकि: इसका अर्थ है संदर्भ के वर्तमान मूल्य से पहुंच योग्य है जिसके लिए इस रीफ्लॉग में पुराने मान हैं। यही है, अगर हम master के लिए reflog पर देख रहे हैं, हम प्रतिबद्ध है कि master की पहचान करता है (जैसे, 1234567), फिर देखें कि वह master के लिए प्रत्येक reflog प्रविष्टि (जैसे, [email protected]{27}) से पहुंचा जा सकता प्रतिबद्ध (है कि विशेष रूप से है 1234567 फिर से)।

यह विशेष नाम भ्रम आपको POSIX मानकीकरण लोगों द्वारा लाया गया है। :-) st_birthtimespec फ़ील्ड struct timespec है, जो दोनों सेकंड और नैनोसेकंड रिकॉर्ड करता है।

+0

ध्यान दें कि रीफ्लॉग प्रविष्टियां अंततः कचरा-एकत्रित होती हैं। ['Git gc' दस्तावेज़] के रूप में (https://www.kernel.org/pub/software/scm/git/docs/git-gc.html) कहता है, वैकल्पिक कॉन्फ़िगरेशन चर 'gc.reflogExpire' डिफ़ॉल्ट पर 90 दिन, और 'gc.reflogExpireUnreachable' 30 दिनों तक डिफ़ॉल्ट है। रीफ्लॉग में पहुंच योग्य और पहुंच योग्य प्रविष्टियां हटा दी जाएंगी यदि वे 'git gc' चलाए जाने पर उन चर से अधिक पुराने हैं। –

+0

@ रोरीओकेन: दाएं; मैंने इसे दस्तावेज लिंक पर छोड़ दिया, लेकिन शायद मुझे इसका जवाब सीधे जवाब में देना चाहिए? – torek

+0

हां, मुझे लगता है कि प्रश्न के शीर्षक को सीधे यह कहकर उपयोगी हो सकता है कि 'git gc' कभी-कभी प्रतिबद्धता को हटा देगा। यह सुझाव देने से भी बच जाएगा कि 'गिट रीफ्लॉग' एकमात्र कमांड है जो रीफ्लॉग प्रविष्टियों को हटा देता है। हालांकि, आपके उत्तर में यह लिखना * वह * महत्वपूर्ण नहीं है, क्योंकि पाठकों को इन टिप्पणियों से वही जानकारी मिल सकती है। –

संबंधित मुद्दे