كيفية استرداد كائنات Git المتضررة بسبب فشل القرص الصلب؟

StackOverflow https://stackoverflow.com/questions/801577

  •  03-07-2019
  •  | 
  •  

سؤال

لقد واجهت فشلاً في القرص الصلب مما أدى إلى تلف بعض ملفات مستودع Git.عند الجري 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

لدي نسخ احتياطية من المستودع، لكن النسخة الاحتياطية الوحيدة التي تتضمن ملف الحزمة قد تعرضت للتلف بالفعل.لذلك أعتقد أنه يتعين علي إيجاد طريقة لاسترداد الكائنات الفردية من نسخ احتياطية مختلفة وتوجيه Git بطريقة ما لإنتاج حزمة جديدة تحتوي على الكائنات الصحيحة فقط.

هل يمكن أن تعطيني تلميحات حول كيفية إصلاح المستودع الخاص بي؟

هل كانت مفيدة؟

المحلول

في بعض النسخ الاحتياطية السابقة، قد تكون معبأة الأشياء السيئة في ملفات مختلفة أو قد تكون كائنات فضفاضة حتى الان. لذلك قد يتم استرداد الأشياء الخاصة بك.

ويبدو أن هناك عدد قليل من الأشياء السيئة في قاعدة البيانات الخاصة بك. لذلك يمكن أن تفعل ذلك بالطريقة اليدوية.

وبسبب 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

وبطبيعة الحال، وأود أن احتياطية نسخة العمل الأصلي قبل البدء في هذه العملية.

وأيضا، وإلقاء نظرة على الموقع كيفية استرداد تلف كائن النقطة .

نصائح أخرى

Banengusk وقد وضع لي على الطريق الصحيح. للإشارة أخرى، أريد أن الرد على الخطوات التي اتخذت لإصلاح بلدي الفساد مستودع. كنت محظوظا بما فيه الكفاية للعثور على جميع الأشياء اللازمة سواء في حزم القديمة أو في النسخ الاحتياطي المخزون.

# 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!

جرب الأوامر التالية في البداية (أعد تشغيلها مرة أخرى إذا لزم الأمر):

$ 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 أو tag -d العادية، لأنها ستموت إذا لاحظ git الفساد.لذا استخدم أمر السباكة git update-ref -d $ref بدلاً من ذلك.لاحظ أنه في حالة الفروع المحلية، قد يترك هذا الأمر تكوين فرع قديمًا في .git/config.يمكن حذفه يدويًا (ابحث عن قسم [الفرع "$ref"]).

  • بعد تنظيف كافة المراجع، قد يظل هناك عمليات مكسورة في عملية إعادة التسجيل.يمكنك مسح جميع عمليات إعادة التسجيل باستخدام git reflog انتهاء الصلاحية --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 rev.) ثم استخدم git reflogنتهي --expire=now $ref في كل منها.عند اختفاء جميع المراجع وإعادة التسجيل المعطلة، قم بتشغيل git fsck --full للتأكد من نظافة المستودع.الأشياء المتدلية على ما يرام.


يمكنك العثور أدناه على الاستخدام المتقدم للأوامر التي من المحتمل أن تتسبب في فقدان بياناتك في مستودع git الخاص بك إذا لم يتم استخدامها بحكمة، لذا قم بعمل نسخة احتياطية قبل أن تسبب المزيد من الأضرار لبوابتك عن طريق الخطأ.حاول على مسؤوليتك الخاصة إذا كنت تعرف ما تفعله.


لسحب الفرع الحالي أعلى الفرع العلوي بعد الجلب:

$ 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.


هناك فكرة أخرى تتمثل في فك ضغط جميع الكائنات من ملفات الحزمة لإعادة إنشاء جميع الكائنات داخل .git/objects، لذا حاول تشغيل الأوامر التالية داخل المستودع الخاص بك:

$ 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 -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

أنظر أيضا:

فيما يلي الخطوات التي اتبعتها للتعافي من كائن blob التالف.

1) تحديد النقطة الفاسدة

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

النقطة الفاسدة هي 241091723c324aed77b2d35f97a05e856b319efd

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

التجزئة الأصل هو 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180.

4) احصل على اسم الملف المطابق لـ blob

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

ابحث عن هذا الملف المعين في نسخة احتياطية أو في مستودع git الأولي (في حالتي هو dump.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)

وبوابة الخروج يمكن اختيار فعلا الملفات الفردية من المراجعة. مجرد إعطائها ارتكاب التجزئة واسم الملف. معلومات أكثر تفصيلا <لأ href = "http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/" يختلط = "نوفولو noreferrer "> هنا.

وأعتقد أن أسهل طريقة لإصلاح هذا هو بأمان العودة إلى أحدث نسخة احتياطية uncommited ثم انتقائي انتقاء ملفات تالفة من يرتكب أحدث. حظا سعيدا!

وهنا اثنين من الوظائف التي يمكن أن تساعد في حالة تلف النسخة الاحتياطية، أو كان لديك عدد قليل من النسخ الاحتياطي التالفة جزئيا وكذلك (وهذا قد يحدث إذا كنت النسخ الاحتياطي للكائنات تالف).

وتشغيل كل من الريبو كنت تحاول التعافي.

والتحذير القياسية: فقط استخدام إذا كنت يائسة حقا وكنت قد احتياطيا الخاص بك (تالفة) الريبو. هذا قد لا حل أي شيء، ولكن على الأقل يجب تسليط الضوء على مستوى الفساد.

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

ولقد تمكنت من حل هذه المشكلة لإضافة بعض التغيير مثل بوابة إضافة -A وبوابة ارتكاب مرة أخرى.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top