web-dev-qa-db-ja.com

ハードディスクの故障により破損した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に正しいオブジェクトのみを含む新しいパックを作成するよう指示する必要があると思います。

リポジトリを修正する方法を教えてください。

91
Christian

以前のバックアップでは、不良オブジェクトが別のファイルにパックされていたり、まだルーズオブジェクトである可能性があります。したがって、オブジェクトが回復される可能性があります。

データベースにいくつかの不良オブジェクトがあるようです。したがって、手動で行うことができます。

git hash-objectgit 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を使用して、現在のリポジトリに再度書き込みます。

タイプがコミットの場合:git showgit cat-file、およびgit commit-treeでも同じです。

もちろん、このプロセスを開始する前に、元の作業コピーをバックアップします。

また、 破損したBlobオブジェクトを回復する方法 もご覧ください。

81
Daniel Fanjul

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!
38
Christian

最初に次のコマンドを試してください(必要に応じて再実行してください):

$ 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
    

    そして、そのファイルのログ全体が表示されます(あなたが持っていたツリーはトップレベルのツリーではないかもしれないので、自分でどのサブディレクトリにあったかを把握する必要があります)ハッシュオブジェクトを持つオブジェクトが再び見つかりません。

  • コミット、ツリー、またはblobが欠落しているすべての参照のリストを取得するには:

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

    通常のbranch -dまたはtag -dコマンドを使用してこれらの参照の一部を削除することはできない場合があります。これは、gitが破損に気付いた場合に死ぬためです。そのため、代わりに配管コマンドgit update-ref -d $ refを使用してください。ローカルブランチの場合、このコマンドは.git/configに古いブランチ設定を残す可能性があることに注意してください。手動で削除できます([branch "$ ref"]セクションを探します)。

  • すべてのrefがクリーンになった後、reflogにコミットが壊れている可能性があります。 git reflog expire --expire = now --allを使用して、すべてのreflogをクリアできます。すべてのreflogを失いたくない場合は、個々のrefで壊れたreflogを検索できます。

    $ (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を使用します。壊れたrefと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

こちらもご覧ください:

15
kenorb

破損した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)破損したブロブを安全な場所に移動します(念のため)

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

親ハッシュは716831e1a6c8d3e6b2b541d21c4748cc0ce718です。

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)
2
Jonathan Maim

バックアップが破損している場合、または一部破損したバックアップがいくつかある場合に役立つ2つの機能を次に示します(破損したオブジェクトをバックアップする場合に発生する可能性があります)。

回復しようとしているリポジトリで両方を実行します。

標準の警告:本当に必死で、(破損した)リポジトリをバックアップした場合にのみ使用します。これは何も解決しないかもしれませんが、少なくとも破損のレベルを強調する必要があります。

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
1
go2null

Gitチェックアウトでは、実際にリビジョンから個々のファイルを選択できます。コミットハッシュとファイル名を指定するだけです。詳細情報 こちら

これを安全に修正する最も簡単な方法は、最新のコミットされていないバックアップに戻り、新しいコミットから破損していないファイルを選択的に選択することだと思います。幸運を!

1
Tim Lin

この問題を解決して、git add -Aやgit commitなどの変更を再度追加しました。

0
Dmitriy S