हार्ड डिस्क विफलता से क्षतिग्रस्त गिट वस्तुओं को कैसे पुनर्प्राप्त करें?


92

मुझे एक हार्ड डिस्क विफलता मिली है, जिसके परिणामस्वरूप गिट रिपॉजिटरी की कुछ फाइलें क्षतिग्रस्त हो गई हैं। दौड़ते समय git fsck --fullमुझे निम्नलिखित आउटपुट मिलते हैं:

error: .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack SHA1 checksum mismatch
error: index CRC mismatch for object 6c8cae4994b5ec7891ccb1527d30634997a978ee from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack at offset 97824129
error: inflate: data stream error (invalid code lengths set)
error: cannot unpack 6c8cae4994b5ec7891ccb1527d30634997a978ee from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack at offset 97824129
error: inflate: data stream error (invalid stored block lengths)
error: failed to read object 0dcf6723cc69cc7f91d4a7432d0f1a1f05e77eaa at offset 276988017 from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack
fatal: object 0dcf6723cc69cc7f91d4a7432d0f1a1f05e77eaa is corrupted

मेरे पास रिपॉजिटरी का बैकअप है, लेकिन एकमात्र बैकअप जिसमें पैक फ़ाइल शामिल है, वह पहले से ही क्षतिग्रस्त है। इसलिए मुझे लगता है कि मुझे अलग-अलग बैकअप से एकल ऑब्जेक्ट को पुनः प्राप्त करने का एक तरीका ढूंढना होगा और किसी तरह गिट को केवल सही ऑब्जेक्ट के साथ एक नया पैक बनाने का निर्देश देना होगा।

क्या आप कृपया मुझे संकेत दे सकते हैं कि मैं अपने भंडार को कैसे ठीक करूं?


2
यह सिर्फ मेरे साथ हुआ। मैं गिट ऑब्जेक्ट्स के साथ गड़बड़ नहीं करना चाहता ... इसलिए रिमोट रिपॉजिटरी से एक नए फ़ोल्डर में प्रोजेक्ट को फिर से क्लोन किया, और फिर मेरे समस्याग्रस्त रिपॉजिटरी ( .gitपाठ्यक्रम के फ़ोल्डर को छोड़कर ) से सभी फाइलों को नए सिरे से क्लोन किए गए रेपो में कॉपी करें। ... और फिर git statusनए रेपो में किया ... जीआईटी ने मेरी फाइलों में सभी प्रभावित परिवर्तनों का सही पता लगाया और मैं अपना काम फिर से शुरू कर सकता हूं।
रोजी कासिम

जवाबों:


82

पिछले कुछ बैकअप में, आपकी खराब वस्तुएं अलग-अलग फ़ाइलों में पैक की गई हो सकती हैं या अभी तक ढीली वस्तुएं हो सकती हैं। तो आपकी वस्तुएँ पुनः प्राप्त हो सकती हैं।

ऐसा लगता है कि आपके डेटाबेस में कुछ खराब वस्तुएं हैं। इसलिए आप इसे मैनुअल तरीके से कर सकते हैं।

की वजह से git hash-object, git mktreeऔर git commit-treeवस्तुओं को न लिखें क्योंकि वे पैक में पाए जाते हैं, फिर ऐसा करना शुरू करें:

mv .git/objects/pack/* <somewhere>
for i in <somewhere>/*.pack; do
  git unpack-objects -r < $i
done
rm <somewhere>/*

(आपके पैक को भंडार से बाहर ले जाया जाता है, और इसमें फिर से पैक किया जाता है; केवल अच्छी वस्तुएं अब डेटाबेस में हैं)

तुम कर सकते हो:

git cat-file -t 6c8cae4994b5ec7891ccb1527d30634997a978ee

और वस्तु के प्रकार की जाँच करें।

यदि प्रकार बूँद है: पिछले बैकअप से फ़ाइल की सामग्री को पुनर्प्राप्त करें ( git showया git cat-fileया git unpack-fileफिर; तो आप git hash-object -wअपने वर्तमान भंडार में ऑब्जेक्ट को फिर से लिख सकते हैं ।

यदि प्रकार पेड़ है: आप git ls-treeपिछले बैकअप से पेड़ को पुनर्प्राप्त करने के लिए उपयोग कर सकते हैं ; फिर git mktreeइसे अपने वर्तमान भंडार में फिर से लिखने के लिए।

यदि प्रकार प्रतिबद्ध है: उसी के साथ git show, git cat-fileऔर git commit-tree

बेशक, मैं इस प्रक्रिया को शुरू करने से पहले आपकी मूल कार्य प्रतिलिपि का बैकअप ले लूंगा।

इसके अलावा, हाउ टू रिकवर करप्टेड ब्लॉब ऑब्जेक्ट पर एक नज़र डालें ।


1
धन्यवाद, कि मुझे बचा लिया! मैं एक अलग उत्तर के रूप में अपने सटीक कदम पोस्ट करूंगा।
ईसाई

बस एक सुधार: "किया" के साथ समाप्त होता है और "अंत" नहीं।
फेलिप

मैं ऐसा करने की कोशिश कर रहा हूं, लेकिन .git/objects/pack/खाली है
kirill_igum

मेरे लिए ए; git अनपैक-ऑब्जेक्ट्स -r <$ i
मिथ्रंदिर

@mithrandir: यदि आपने पिछली पंक्ति में 'किया' रखा है: हाँ, आपको अर्धविराम की आवश्यकता है। यदि आप ठीक वही लिखते हैं जो मैंने लिखा है, तो आप नहीं करते।
डैनियल फंजुल

38

बेंगेंगस्क मुझे सही रास्ते पर डाल रहा था। आगे के संदर्भ के लिए, मैं अपने रिपॉजिटरी भ्रष्टाचार को ठीक करने के लिए उठाए गए कदमों को पोस्ट करना चाहता हूं। मैं भाग्यशाली था कि सभी आवश्यक वस्तुओं को पुराने पैक या रिपॉजिटरी बैकअप में पाया गया।

# Unpack last non-corrupted pack
$ mv .git/objects/pack .git/objects/pack.old
$ git unpack-objects -r < .git/objects/pack.old/pack-012066c998b2d171913aeb5bf0719fd4655fa7d0.pack
$ git log
fatal: bad object HEAD

$ cat .git/HEAD 
ref: refs/heads/master

$ ls .git/refs/heads/

$ cat .git/packed-refs 
# pack-refs with: peeled 
aa268a069add6d71e162c4e2455c1b690079c8c1 refs/heads/master

$ git fsck --full 
error: HEAD: invalid sha1 pointer aa268a069add6d71e162c4e2455c1b690079c8c1
error: refs/heads/master does not point to a valid object!
missing blob 75405ef0e6f66e48c1ff836786ff110efa33a919
missing blob 27c4611ffbc3c32712a395910a96052a3de67c9b
dangling tree 30473f109d87f4bcde612a2b9a204c3e322cb0dc

# Copy HEAD object from backup of repository
$ cp repobackup/.git/objects/aa/268a069add6d71e162c4e2455c1b690079c8c1 .git/objects/aa
# Now copy all missing objects from backup of repository and run "git fsck --full" afterwards
# Repeat until git fsck --full only reports dangling objects

# Now garbage collect repo
$ git gc
warning: reflog of 'HEAD' references pruned commits
warning: reflog of 'refs/heads/master' references pruned commits
Counting objects: 3992, done.
Delta compression using 2 threads.
fatal: object bf1c4953c0ea4a045bf0975a916b53d247e7ca94 inconsistent object length (6093 vs 415232)
error: failed to run repack

# Check reflogs...
$ git reflog

# ...then clean
$ git reflog expire --expire=0 --all

# Now garbage collect again
$ git gc       
Counting objects: 3992, done.
Delta compression using 2 threads.
Compressing objects: 100% (3970/3970), done.
Writing objects: 100% (3992/3992), done.
Total 3992 (delta 2060), reused 0 (delta 0)
Removing duplicate objects: 100% (256/256), done.
# Done!

3
इसे जोड़ना: यदि बैकअप में एक पैकेट में गायब फ़ाइलें हैं, तो पैक से एक बूँद प्राप्त करने का उचित तरीका है 'गिट कैट-फाइल ब्लॉब <SHA1>> file.dat', और इसे क्षतिग्रस्त में वापस लाने के लिए। रेपो, डैनियल के जवाब में 'git हैश-ऑब्जेक्ट -w file.dat' करें।
एमिल स्टायरके

आप अंतिम गैर-दूषित पैक कैसे खोज सकते हैं? धन्यवाद
बजे रोमेन ऑगोर्री

18

पहले निम्नलिखित आदेशों की कोशिश करें (यदि आवश्यक हो तो फिर से चलाएं):

$ git fsck --full
$ git gc
$ git gc --prune=today
$ git fetch --all
$ git pull --rebase

और फिर आप अभी भी समस्या है, कोशिश कर सकते हैं:

  • सभी भ्रष्ट वस्तुओं को हटा दें, जैसे

    fatal: loose object 91c5...51e5 (stored in .git/objects/06/91c5...51e5) is corrupt
    $ rm -v .git/objects/06/91c5...51e5
    
  • सभी खाली वस्तुओं को हटा दें, जैसे

    error: object file .git/objects/06/91c5...51e5 is empty
    $ find .git/objects/ -size 0 -exec rm -vf "{}" \;
    
  • एक "टूटी हुई कड़ी" संदेश की जाँच करें:

    git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
    

    यह आपको बताता है कि भ्रष्ट बूँद किस फ़ाइल से आई है!

  • फ़ाइल को पुनर्प्राप्त करने के लिए, आप वास्तव में भाग्यशाली हो सकते हैं, और यह वह संस्करण हो सकता है जिसे आपने पहले से ही अपने काम के पेड़ में देख लिया है:

    git hash-object -w my-magic-file
    

    फिर से, और अगर यह लापता SHA1 (4b945 ..) का उत्पादन करता है तो आप अब सब कर चुके हैं!

  • यह मानते हुए कि यह कुछ पुराना संस्करण था जो टूट गया था, इसे करने का सबसे आसान तरीका है:

    git log --raw --all --full-history -- subdirectory/my-magic-file
    

    और वह आपको उस फ़ाइल के लिए पूरी लॉग दिखाएगा (कृपया महसूस करें कि आपके पास जो पेड़ था वह शीर्ष स्तर का पेड़ नहीं हो सकता है, इसलिए आपको यह पता लगाने की आवश्यकता है कि यह आपके पास किस उपनिर्देशिका पर है), तो अब आप इसे फिर से बना सकते हैं हैश-ऑब्जेक्ट के साथ फिर से गायब वस्तु।

  • लापता कॉम, पेड़ों या बूँद के साथ सभी रेफ की सूची प्राप्त करने के लिए:

    $ git for-each-ref --format='%(refname)' | while read ref; do git rev-list --objects $ref >/dev/null || echo "in $ref"; done
    

    हो सकता है कि नियमित शाखा -d या टैग -d कमांड का उपयोग करते हुए उनमें से कुछ को हटाना संभव न हो, क्योंकि भ्रष्टाचार की सूचना मिलने पर वे मर जाएंगे। इसलिए प्लंबिंग कमांड git update-ref -d $ ref के स्थान पर उपयोग करें। ध्यान दें कि स्थानीय शाखाओं के मामले में, यह कमांड .it / config में बासी शाखा विन्यास को पीछे छोड़ सकती है। इसे मैन्युअल रूप से हटाया जा सकता है ([शाखा "$ रेफ"] अनुभाग के लिए देखें)।

  • सभी Refs साफ होने के बाद भी reflog में टूटे हुए कमिट्स हो सकते हैं। आप git reflog expire --expire = now --all का उपयोग करके सभी रिफ्लेक्स को साफ कर सकते हैं। यदि आप अपने सभी रिफ्लॉग्स को खोना नहीं चाहते हैं, तो आप टूटे हुए रिफॉल्स के लिए अलग-अलग रेफरी खोज सकते हैं:

    $ (echo HEAD; git for-each-ref --format='%(refname)') | while read ref; do git rev-list -g --objects $ref >/dev/null || echo "in $ref"; done
    

    (नोट-रि-लिस्ट को जोड़ने के लिए -g विकल्प पर ध्यान दें।) फिर, git reflog expire --expire = का उपयोग करें, अब उनमें से प्रत्येक पर $ ref। जब सभी टूटे हुए रिफ्लेक्स और रिफ्लॉज चले जाते हैं, तो रिपॉजिटरी साफ है यह जांचने के लिए git fsck --full चलाएं। डंकलिंग ऑब्जेक्ट ठीक हैं।


नीचे आप उन कमांडों का उन्नत उपयोग पा सकते हैं जो संभावित रूप से आपके गिट रिपॉजिटरी में आपके डेटा के खो जाने का कारण बन सकते हैं यदि बुद्धिमानी से उपयोग नहीं किया जाता है, तो इससे पहले कि आप गलती से आपके गिट को नुकसान पहुंचाएं, इससे पहले एक बैकअप बनाएं। यदि आप जानते हैं कि आप क्या कर रहे हैं तो अपने जोखिम पर प्रयास करें।


लाने के बाद अपस्ट्रीम शाखा के शीर्ष पर वर्तमान शाखा खींचने के लिए:

$ git pull --rebase

आप नई शाखा की जांच करने और पुराने को हटाने का भी प्रयास कर सकते हैं:

$ git checkout -b new_master origin/master

हटाने के लिए git में दूषित ऑब्जेक्ट को खोजने के लिए, निम्न आदेश का प्रयास करें:

while [ true ]; do f=`git fsck --full 2>&1|awk '{print $3}'|sed -r 's/(^..)(.*)/objects\/\1\/\2/'`; if [ ! -f "$f" ]; then break; fi; echo delete $f; rm -f "$f"; done

OSX के लिए, के sed -Eबजाय का उपयोग करें sed -r


अन्य विचार यह है कि सभी ऑब्जेक्ट्स को पैक फ़ाइलों से खोलना है। सभी ऑब्जेक्ट्स को .गित / ऑब्जेक्ट्स के अंदर पुन: उत्पन्न करने के लिए, इसलिए अपनी रिपॉजिटरी के भीतर निम्नलिखित कमांड्स चलाने की कोशिश करें:

$ cp -fr .git/objects/pack .git/objects/pack.bak
$ for i in .git/objects/pack.bak/*.pack; do git unpack-objects -r < $i; done
$ rm -frv .git/objects/pack.bak

यदि ऊपर मदद नहीं करता है, तो आप किसी अन्य रेपो से git ऑब्जेक्ट्स को rsync या कॉपी करने का प्रयास कर सकते हैं, जैसे

$ rsync -varu git_server:/path/to/git/.git local_git_repo/
$ rsync -varu /local/path/to/other-working/git/.git local_git_repo/
$ cp -frv ../other_repo/.git/objects .git/objects

टूटी हुई शाखा को ठीक करने के लिए जब चेकआउट करने की कोशिश की जा रही है:

$ git checkout -f master
fatal: unable to read tree 5ace24d474a9535ddd5e6a6c6a1ef480aecf2625

इसे हटाने की कोशिश करें और फिर से अपस्ट्रीम से चेकआउट करें:

$ git branch -D master
$ git checkout -b master github/master

मामले में अगर गिट आपको अलग राज्य में मिलता है, तो चेकआउट करें masterऔर इसे अलग शाखा में मिला दें।


एक अन्य विचार मौजूदा मास्टर को पुनरावर्ती रूप से वापस करना है:

$ git reset HEAD --hard
$ git rebase -s recursive -X theirs origin/master

यह सभी देखें:


2

यहाँ एक भ्रष्ट बूँद वस्तु से उबरने के लिए मैंने जिन चरणों का पालन किया है।

1) भ्रष्ट बूँद को पहचानें

git fsck --full
  error: inflate: data stream error (incorrect data check)
  error: sha1 mismatch 241091723c324aed77b2d35f97a05e856b319efd
  error: 241091723c324aed77b2d35f97a05e856b319efd: object corrupt or missing
  ...

भ्रष्ट बूँद 241091723c324aed77b2d35f97a05e856b319fdd है

2) भ्रष्ट बूँद को एक सुरक्षित स्थान पर ले जाएं (बस मामले में)

mv .git/objects/24/1091723c324aed77b2d35f97a05e856b319efd ../24/

3) भ्रष्ट बूँद के माता-पिता प्राप्त करें

git fsck --full
  Checking object directories: 100% (256/256), done.
  Checking objects: 100% (70321/70321), done.
  broken link from    tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
              to    blob 241091723c324aed77b2d35f97a05e856b319efd

पैरेंट हैश 0716831e1a6c8d3e6b2b541d21c4748cc0807180 है

4) भ्रष्ट बूँद के संगत फ़ाइल नाम प्राप्त करें

git ls-tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
  ...
  100644 blob 241091723c324aed77b2d35f97a05e856b319efd    dump.tar.gz
  ...

इस विशेष फ़ाइल को एक बैकअप में या अपस्ट्रीम गिट रिपॉजिटरी में खोजें (मेरे मामले में यह डंप हैtar.gz )। फिर इसे अपने स्थानीय भंडार के अंदर कहीं कॉपी करें।

5) git ऑब्जेक्ट डेटाबेस में पहले से दूषित फ़ाइल जोड़ें

git hash-object -w dump.tar.gz

6) जश्न मनाएं!

git gc
  Counting objects: 75197, done.
  Compressing objects: 100% (21805/21805), done.
  Writing objects: 100% (75197/75197), done.
  Total 75197 (delta 52999), reused 69857 (delta 49296)

यह मेरे लिए काम नहीं किया। चरण 4 में परिणाम आया git ls-tree 9504a07fb803edfdf0c1dd99c5d561274af87982 error: Could not read 19505205fd1f219993da9b75846fff3cf432152d, और मैंने भी चरण 2 के बिना इसे फिर से कोशिश की, और इसके परिणामस्वरूपgit ls-tree 9504a07fb803edfdf0c1dd99c5d561274af87982 error: inflate: data stream error (invalid stored block lengths) fatal: failed to read object 19505205fd1f219993da9b75846fff3cf432152d: Invalid argument
रयान

1

Git चेकआउट वास्तव में एक संशोधन से अलग-अलग फ़ाइलों को निकाल सकता है। बस इसे कमिट हैश और फ़ाइल का नाम दें। अधिक विस्तृत जानकारी यहाँ।

मुझे लगता है कि इसे सुरक्षित रूप से ठीक करने का सबसे आसान तरीका है कि नए अनकम्यूटेड बैकअप को वापस कर दिया जाए और फिर नए कमिट से अनियंत्रित फ़ाइलों को चुन लिया जाए। सौभाग्य!


1

यहां दो कार्य हैं जो आपके बैकअप को दूषित होने पर मदद कर सकते हैं, या आपके पास कुछ आंशिक रूप से दूषित बैकअप भी हैं (यदि आप दूषित वस्तुओं का बैकअप लेते हैं तो ऐसा हो सकता है)।

दोनों को पुनर्प्राप्त करने की कोशिश कर रहे रेपो में चलाएं।

मानक चेतावनी: केवल तभी उपयोग करें जब आप वास्तव में हताश हों और आपने अपने (भ्रष्ट) रेपो का समर्थन किया हो। यह कुछ भी हल नहीं कर सकता है, लेकिन कम से कम भ्रष्टाचार के स्तर को उजागर करना चाहिए।

fsck_rm_corrupted() {
    corrupted='a'
    while [ "$corrupted" ]; do
        corrupted=$(                                  \
        git fsck --full --no-dangling 2>&1 >/dev/null \
            | grep 'stored in'                          \
            | sed -r 's:.*(\.git/.*)\).*:\1:'           \
        )
        echo "$corrupted"
        rm -f "$corrupted"
    done
}

if [ -z "$1" ]  || [ ! -d "$1" ]; then
    echo "'$1' is not a directory. Please provide the directory of the git repo"
    exit 1
fi

pushd "$1" >/dev/null
fsck_rm_corrupted
popd >/dev/null

तथा

unpack_rm_corrupted() {
    corrupted='a'
    while [ "$corrupted" ]; do
        corrupted=$(                                  \
        git unpack-objects -r < "$1" 2>&1 >/dev/null \
            | grep 'stored in'                          \
            | sed -r 's:.*(\.git/.*)\).*:\1:'           \
        )
        echo "$corrupted"
        rm -f "$corrupted"
    done
}

if [ -z "$1" ]  || [ ! -d "$1" ]; then
    echo "'$1' is not a directory. Please provide the directory of the git repo"
    exit 1
fi

for p in $1/objects/pack/pack-*.pack; do
    echo "$p"
    unpack_rm_corrupted "$p"
done

0

मैंने इस समस्या को कुछ परिवर्तन जोड़ने के लिए हल किया है जैसे git add -A और फिर से कमिट कमिट।

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