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


92

하드 디스크 오류가 발생하여 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에게 올바른 개체 만있는 새 팩을 생성하도록 지시해야한다고 생각합니다.

내 저장소를 수정하는 방법에 대한 힌트를 줄 수 있습니까?


2
이것은 나에게 일어난 일입니다. git 개체를 엉망으로 만들고 싶지 않으므로 원격 저장소의 프로젝트를 새 폴더로 다시 복제 한 다음 문제가있는 저장소 ( .git물론 폴더 제외)의 모든 파일을 새로 복제 된 저장소로 복사합니다. ... 그런 다음 git status새 저장소에서 수행했습니다 ... git은 내 파일의 영향을받는 모든 변경 사항을 올바르게 감지하고 작업을 다시 시작할 수 있습니다.
Rosdi Kasim

답변:


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

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

유형이 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 개체를 복구하는 방법을 살펴보십시오 .


1
감사합니다, 저를 구했습니다! 정확한 단계를 별도의 답변으로 게시하겠습니다.
Christian

수정 : 명령은 "끝"이 아니라 "완료"로 끝납니다.
Felipe

나는 이것을하려고하는데 .git/objects/pack/비어있다
kirill_igum 2011

나를 위해; 자식 실종 된 압축 풀기 - 객체 -r <$ 내가
mithrandir

@mithrandir : 이전 줄에 'done'을 넣으면 예, 세미콜론이 필요합니다. 내가 쓴 내용을 정확히 입력하면 입력하지 않습니다.
다니엘 Fanjul

38

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!

3
여기에 추가 : 백업에 팩에 누락 된 파일이있는 경우 팩에서 blob을 가져 오는 올바른 방법은 'git cat-file blob <SHA1>> file.dat'이며 손상된 파일로 다시 가져 오는 것입니다. repo, Daniel의 대답과 같이 'git hash-object -w file.dat'를 수행하십시오.
Emil Styrke 2013 년

손상되지 않은 마지막 팩을 어떻게 찾습니까? 감사
로맹 Ourgorry

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
    

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

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

    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이 손상을 발견하면 죽기 때문입니다. 따라서 배관 명령 git update-ref -d $ ref를 대신 사용하십시오. 로컬 브랜치의 경우이 명령은 .git / config에 오래된 브랜치 구성을 남길 수 있습니다. 수동으로 삭제할 수 있습니다 ([branch "$ ref"] 섹션을 찾으십시오).

  • 모든 ref가 정리 된 후에도 reflog에 여전히 깨진 커밋이있을 수 있습니다. git reflog expire --expire = now --all을 사용하여 모든 reflog를 지울 수 있습니다. 모든 리플 로그를 잃지 않으려면 개별 ref에서 깨진 리플 로그를 검색 할 수 있습니다.

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

    (git rev-list에 추가 된 -g 옵션을 참고하십시오.) 그런 다음 각각에 git reflog expire --expire = now $ ref를 사용하십시오. 모든 깨진 refs 및 reflog가 사라지면 저장소가 깨끗한 지 확인하기 위해 git fsck --full을 실행하십시오. 매달린 물체는 괜찮습니다.


아래에서 현명하게 사용하지 않을 경우 잠재적으로 git 저장소의 데이터를 잃을 수있는 명령의 고급 사용법을 찾을 수 있으므로 실수로 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하거나 복사 할 수 있습니다.

$ 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

git이 분리 된 상태로 들어가면 분리 master된 분기를 확인 하고 병합하십시오.


또 다른 아이디어는 기존 마스터를 재귀 적으로 리베이스하는 것입니다.

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

또한보십시오:


2

다음은 손상된 Blob 개체에서 복구하기 위해 수행 한 단계입니다.

1) 손상된 Blob 식별

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

손상된 blob은 241091723c324aed77b2d35f97a05e856b319efd입니다.

2) 손상된 blob을 안전한 장소로 이동 (만약 경우에 대비)

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

3) 손상된 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

부모 해시는 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)

이것은 나를 위해 작동하지 않았습니다. 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 및 git commit과 같은 변경 사항을 다시 추가했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.