development

하드 디스크 오류로 손상된 Git 개체를 복구하는 방법은 무엇입니까?

big-blog 2020. 9. 1. 07:52
반응형

하드 디스크 오류로 손상된 Git 개체를 복구하는 방법은 무엇입니까?


하드 디스크 오류가 발생하여 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

개체의 유형을 확인하십시오.

유형이 blob 인 경우 : git show또는 git cat-file또는 사용 하여 이전 백업에서 파일의 내용을 검색 git unpack-file한 다음 git hash-object -w현재 저장소에서 객체를 다시 작성할 수 있습니다 .

유형이 트리 인 경우 : git ls-tree이전 백업에서 트리를 복구하는 데 사용할 수 있습니다. 그런 다음 git mktree현재 저장소에 다시 작성하십시오.

유형이 commit 인 경우 git show, git cat-file및과 동일 git commit-tree합니다.

물론이 프로세스를 시작하기 전에 원본 작업 복사본을 백업합니다.

또한 손상된 Blob 개체를 복구하는 방법을 살펴보십시오 .


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
    

    이것은 손상된 blob이 어떤 파일에서 왔는지 알려줍니다!

  • 파일을 복구하려면 정말 운이 좋을 수 있으며 작업 트리에서 이미 체크 아웃 한 버전 일 수 있습니다.

    git hash-object -w my-magic-file
    

    다시, 누락 된 SHA1 (4b945 ..)이 출력되면 이제 모든 작업이 완료된 것입니다!

  • assuming that it was some older version that was broken, the easiest way to do it is to do:

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

    and that will show you the whole log for that file (please realize that the tree you had may not be the top-level tree, so you need to figure out which subdirectory it was in on your own), then you can now recreate the missing object with hash-object again.

  • to get a list of all refs with missing commits, trees or blobs:

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

    It may not be possible to remove some of those refs using the regular branch -d or tag -d commands, since they will die if git notices the corruption. So use the plumbing command git update-ref -d $ref instead. Note that in case of local branches, this command may leave stale branch configuration behind in .git/config. It can be deleted manually (look for the [branch "$ref"] section).

  • After all refs are clean, there may still be broken commits in the reflog. You can clear all reflogs using git reflog expire --expire=now --all. If you do not want to lose all of your reflogs, you can search the individual refs for broken reflogs:

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

    (Note the added -g option to git rev-list.) Then, use git reflog expire --expire=now $ref on each of those. When all broken refs and reflogs are gone, run git fsck --full in order to check that the repository is clean. Dangling objects are Ok.


Below you can find advanced usage of commands which potentially can cause lost of your data in your git repository if not used wisely, so make a backup before you accidentally do further damages to your git. Try on your own risk if you know what you're doing.


To pull the current branch on top of the upstream branch after fetching:

$ git pull --rebase

You also may try to checkout new branch and delete the old one:

$ git checkout -b new_master origin/master

To find the corrupted object in git for removal, try the following command:

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

For OSX, use sed -E instead of sed -r.


Other idea is to unpack all objects from pack files to regenerate all objects inside .git/objects, so try to run the following commands within your repository:

$ 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

If above doesn't help, you may try to rsync or copy the git objects from another repo, e.g.

$ 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

To fix the broken branch when trying to checkout as follows:

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

Try to remove it and checkout from upstream again:

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

In case if git get you into detached state, checkout the master and merge into it the detached branch.


Another idea is to rebase the existing master recursively:

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

See also:


Here are the steps I followed to recover from a corrupt blob object.

1) Identify corrupt blob

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

Corrupt blob is 241091723c324aed77b2d35f97a05e856b319efd

2) Move corrupt blob to a safe place (just in case)

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

3) Get parent of corrupt blob

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

Parent hash is 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180.

4) Get file name corresponding to corrupt blob

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

Find this particular file in a backup or in the upstream git repository (in my case it is dump.tar.gz). Then copy it somewhere inside your local repository.

5) Add previously corrupted file in the git object database

git hash-object -w dump.tar.gz

6) Celebrate!

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)

Git checkout can actually pick out individual files from a revision. Just give it the commit hash and the file name. More detailed info here.

I guess the easiest way to fix this safely is to revert to the newest uncommited backup and then selectively pick out uncorrupted files from newer commits. Good luck!


Here are two functions that may help if your backup is corrupted, or you have a few partially corrupted backups as well (this may happen if you backup the corrupted objects).

Run both in the repo you're trying to recover.

Standard warning: only use if you're really desperate and you have backed up your (corrupted) repo. This might not resolve anything, but at least should highlight the level of corruption.

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

and

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

I have resolved this problem to add some change like git add -A and git commit again.

참고URL : https://stackoverflow.com/questions/801577/how-to-recover-git-objects-damaged-by-hard-disk-failure

반응형