94

ハードディスクに障害が発生したため、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 に正しいオブジェクトのみを含む新しいパックを作成するように指示する方法を見つける必要があると思います。

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

4

8 に答える 8

86

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

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

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 showgit cat-fileおよび と同じgit commit-tree

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

また、How to Recover Corrupted Blob Object もご覧ください。

于 2009-04-29T13:09:54.833 に答える
37

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!
于 2009-05-04T13:46:24.047 に答える
19

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

$ 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
    

    これにより、そのファイルのログ全体が表示されます (ツリーが最上位ツリーではない可能性があることに注意してください。そのため、自分でどのサブディレクトリにあったかを把握する必要があります)。 hash-object を持つオブジェクトが再び見つかりません。

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

    $ 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 コマンドを使用してこれらの ref の一部を削除することはできない場合があります。git が破損に気付くと、これらの ref は削除されるからです。そのため、代わりに配管コマンド git update-ref -d $ref を使用してください。ローカル ブランチの場合、このコマンドは古いブランチ構成を .git/config に残す可能性があることに注意してください。手動で削除できます ([branch "$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 を使用します。壊れた参照と参照ログがすべてなくなったら、リポジトリがクリーンであることを確認するために 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ます。


他のアイデアは、pack ファイルからすべてのオブジェクトをアンパックして、.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して、切り離されたブランチにマージします。


もう 1 つのアイデアは、既存のマスターを再帰的にリベースすることです。

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

以下も参照してください。

于 2014-03-27T17:07:47.503 に答える
2

破損した BLOB オブジェクトから回復するために私が従った手順は次のとおりです。

1) 破損したブロブを特定する

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

親ハッシュは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)
于 2015-10-30T03:51:51.993 に答える
1

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

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

于 2009-04-29T10:01:13.477 に答える
0

Daniel Fanjul による解決策は有望に見えました。そのブロブファイルを見つけて抽出することができました(「git fsck --full --no-dangling」、「git cat-file -t {hash}」、「git show {hash} > file.tmp」)が、 「git hash-object -w file.tmp」でパックファイルを更新しようとすると、正しいハッシュが表示されましたが、エラーが残りました。

そこで、別のアプローチを試すことにしました。単純にローカル リポジトリを削除してリモートからすべてをダウンロードすることはできましたが、ローカル リポジトリの一部のブランチは 8 コミット先であり、それらの変更を失いたくありませんでした。その小さな 6kb の mp3 ファイルなので、完全に削除することにしました。私は多くの方法を試しましたが、ここから最高でした: https://itextpdf.com/en/blog/technical-notes/how-completely-remove-file-git-repository

このコマンド「 git rev-list --objects --all | grep {hash} 」を実行してファイル名を取得しました。次に、バックアップを作成し (3 回失敗したため、バックアップを強くお勧めします)、次のコマンドを実行します。

" java -jar bfg.jar --delete-files {ファイル名} --no-blob-protection . "

ここから bfg.jar ファイルを取得できますhttps://rtyley.github.io/bfg-repo-cleaner/したがって、ドキュメントによると、次にこのコマンドを実行する必要があります。

「git reflog の有効期限 --expire=now --all && git gc --prune=now --aggressive」

そうすると、最後のステップでエラーが発生しました。だから私はバックアップからすべてを回復し、今回はファイルを削除した後、ブランチにチェックアウトし(それがエラーの原因でした)、次にメインにチェックアウトし、コマンドを次々に実行した後にのみ:

"git reflog expire --expire=now --all" "git gc --prune=now --aggressive"

次に、ファイルをその場所に戻してコミットしました。しかし、多くのローカル コミットが変更されたため、サーバーに何もプッシュできませんでした。したがって、サーバー上のすべてをバックアップし(失敗した場合に備えて)、影響を受けたブランチにチェックアウトし、コマンド「git push --force」を実行します。

このケースから私が理解したのは何ですか?GIT は素晴らしいですが、非常に敏感です... 1 つの f... 6kb ファイルを単に無視するオプションが必要です。「git hash-object -w」が機能しなかった理由も含まれていません =( 学んだ教訓、すべてのコミットをプッシュする、待機しない、リポジトリのバックアップを時々行う。また、リポジトリからファイルを削除する方法も知っています。これまでに必要 =)

これが誰かの時間を節約することを願っています

于 2021-01-31T07:21:26.957 に答える