5

tl;dr:HEAD^のツリーが削除され、事前にプッシュされておらず、他のすべてが無傷である場合、そのツリーを復元することは可能ですか?

の一部を誤って削除してしまいました.git。何が欠けているのか完全にはわかりません。

git pushそれが機能しないことを発見すると、次のように実行しましたgit fsck

Checking object directories: 100% (256/256), done.
Checking objects: 100% (1265/1265), done.
broken link from  commit f3419f630546ba02baf43f4ca760b02c0f4a0e6d
              to    tree 29616dfefd2bff59b7fb3177e99b4a1efc7132fa
broken link from  commit ccfe9502e24d2b5195008005d83155197a2dca25
              to    tree 0580c3675560cbfd3f989878a9524e35f53f08e9
broken link from  commit ccfe9502e24d2b5195008005d83155197a2dca25
              to  commit 0bca9b3a9f1dd9106922f5b4ec59cdc00dd6c049
broken link from    tree 6d33d35870281340c7c2f86c6d48c8f133b836bb
              to    blob 226d8a10a623acd943bb8eddd080a5929f3ccb2c
broken link from  commit db238d4a52ee8f18a04c038809bc6587d7643438
              to    tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
missing tree 0580c3675560cbfd3f989878a9524e35f53f08e9
dangling commit 05512f9ac09d932e7d9a11d490c8a2f117c0ca11
missing tree 29616dfefd2bff59b7fb3177e99b4a1efc7132fa
dangling commit 578464dde7d7b8628f77e536b4076cfa491d7602
missing blob 5d351b568abb734605ca4bf446e13cfd87ca9ce8
missing tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
missing commit 0bca9b3a9f1dd9106922f5b4ec59cdc00dd6c049
dangling blob d53a9d0f3364b648edbc4beede022e4594a84c35
missing blob 23db34f729a88c5f5f7fe6e281921f1334f493d1
dangling commit 8dcbde55462ca0c29e0ca339a49db95b43188ef1
dangling blob e59b25b9675625d0e6b8abfa37e955ab46493fd9
missing blob 226d8a10a623acd943bb8eddd080a5929f3ccb2c
dangling commit 85fdaaa579cf1ae2a8874e3e1f3c65d68b478179
dangling commit 075e9d72e90cc8bf3d960edd8376aaae0847f916
missing blob 83fec2ff8cfcaaa06c96917b6973ace96301e932
dangling commit a88e18e1c102d909361738fd70137b3f4a1c7496
dangling blob 9c6f61e0acffe2a1f5322cd2b72c181e95e9de75
dangling commit ca9fe0dd3123a731fc310b2a2285b00ef673de79

したがって、私の推測では、GitHub から復元できる情報が不足しているだけだと思います。私のひざまずいた反応は run でしたがgit fetch、取得する新しいものは何もないと見なされるため、何も出力されずに返されます。

いくつかの方法で開梱を試み.git/objects/pack/pack-ea43d1db155e4502c2250ec1d4608843715c8b1f.packましたが、うまくいきませんでした。例えば:

% git clone --mirror git://github.com/strugee/dots.git # returns bare repo
Cloning into bare repository 'dots.git'...
remote: Counting objects: 1331, done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 1331 (delta 12), reused 0 (delta 0)
Receiving objects: 100% (1331/1331), 402.31 KiB | 197.00 KiB/s, done.
Resolving deltas: 100% (454/454), done.
Checking connectivity... done.
% ls dots.git
config  description  HEAD  hooks  info  objects  packed-refs  refs
% mkdir git-tmp; cd git-tmp
% git init
% git unpack-objects < ../dots.git/objects/pack/pack-ea43d1db155e4502c2250ec1d4608843715c8b1f.pack
error: inflate: data stream error (incorrect data check)
error: inflate returned -3

毎回このエラーが発生しました。(心に留めておいてください: これは--mirrorであるため、 GitHub にあるものの正確なコピーです。そうですよね? どうして破損している可能性がありますか?)

最終的に、パックファイルを実際に解凍する必要がないことに気付きました。それを元のリポジトリにコピーして戻すだけで、Git はそれを問題なく取得します。そう:

% cd ../configs
% cp ../dots.git/objects/pack/pack-ea43d1db155e4502c2250ec1d4608843715c8b1f.* .git/objects/pack/

そして、それはうまくいくように見えました。多くの場合。

% git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (2596/2596), done.
broken link from  commit db238d4a52ee8f18a04c038809bc6587d7643438
              to    tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
dangling commit 05512f9ac09d932e7d9a11d490c8a2f117c0ca11
dangling commit 578464dde7d7b8628f77e536b4076cfa491d7602
missing blob 5d351b568abb734605ca4bf446e13cfd87ca9ce8
missing tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
dangling blob d53a9d0f3364b648edbc4beede022e4594a84c35
dangling commit 8dcbde55462ca0c29e0ca339a49db95b43188ef1
dangling commit 85fdaaa579cf1ae2a8874e3e1f3c65d68b478179
dangling commit 075e9d72e90cc8bf3d960edd8376aaae0847f916
missing blob 83fec2ff8cfcaaa06c96917b6973ace96301e932
dangling commit a88e18e1c102d909361738fd70137b3f4a1c7496
dangling commit ca9fe0dd3123a731fc310b2a2285b00ef673de79

ご覧のとおり、欠落しているリンクは 1 つを除いてすべて修復されました。結局のところ、はまだプッシュしていないdb238dコミット (たまたま ) の ID です。HEAD^このリポジトリの最後の 2 つのコミットは回復不能であり、それらのコミットの内容を再作成する必要があると仮定するのは正しいですか? このシナリオで正しい決定を下しましたか?

4

2 に答える 2

8

git fetch-packを試して 、別のリポジトリから利用可能な不足しているオブジェクトを回復してください。以下の手順。

プッシュされていないコミット、具体的には HEAD^1 の回復のために、私はから始めます

git diff-tree -r HEAD~2^{tree} HEAD^{tree}

変更されたすべてのツリー/ブロブとその SHA のリストが表示されます (これには、HEAD と HEAD^1 の両方からの変更が含まれます)。利用可能な情報の量によっては、不足しているすべてのツリーの一部を再作成できる場合があります。ただし、欠落しているブロブはより問題になります。

の使用git fetch-pack

意図的に破損したリポジトリ

me@myvm:/scratch/corrupt/.git  (GIT_DIR!)$ cd objects/
me@myvm:/scratch/corrupt/.git/objects  (GIT_DIR!)$ ll
total 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 22
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 25
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 info
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 pack
me@myvm:/scratch/corrupt/.git/objects  (GIT_DIR!)$ rm -rf 22

ヘッドの状態が悪いことを確認する

me@myvm:/scratch/corrupt/.git/objects  (GIT_DIR!)$ cd ../../
me@myvm:/scratch/corrupt  (master)$ git status
fatal: bad object HEAD

失われたオブジェクトを回復する

me@myvm:/scratch/corrupt  (master)$ git fetch-pack --all $(git config --get remote.origin.url)
error: refs/heads/master does not point to a valid object!
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: refs/heads/master does not point to a valid object!
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
22ecde746be79c65b27a5cf1dc421764d8ff6e17 HEAD
22ecde746be79c65b27a5cf1dc421764d8ff6e17 refs/heads/master
me@myvm:/scratch/corrupt  (master)$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

失われたオブジェクトが復元されました

me@myvm:/scratch/corrupt  (master)$ ll .git/objects/
total 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:05 22
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 25
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 info
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 pack
me@myvm:/scratch/corrupt  (master)$ 


me@myvm:/scratch/corrupt  (master)$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

壊れたツリー オブジェクトと壊れた BLOB オブジェクトを見つけることができる状態になった場合は、それらを手動で回復できます。任意のブロブに対して行うことができますgit cat-file -p BLOB_SHA。これにより、コンテンツがダンプされます。ファイルの内容を見て、そのファイルが何であるかがわかれば、ファイルの回復に役立ちます。同様git cat-file -p TREE_SHAに、ファイル名と blob SHA を示すツリーをダンプします。この時点で、おそらく部分的なデータから手動でツリーを作成し、オブジェクトをコミットしようとしています。HEAD コミットに問題がない場合は、履歴が欠落しているだけであり、少なくとも最新の状態をカバーする必要があります。

于 2014-10-07T04:04:58.343 に答える
2

したがって、私の推測では、GitHub から復元できる情報が不足しているだけだと思います。

一般的には正しいですが、壊れたリンクがどこから来たのかを正確に特定できれば役に立ちます。

これが、Git 2.10 (2016 年第 3 四半期) を提案するものです。

git fsck --name-objects

commit 90cf590commit 1cd772ccommit 7b35efdcommit 993a21b (2016 年 7 月 17 日) by Johannes Schindelin ( dscho)を参照してください。
( 2016 年 7 月 25 日、コミット 9db3979Junio C Hamanoによってマージされました)gitster

fsck: 必要に応じて、壊れたリンクに関するより役立つ情報を表示します

" git fsck" が壊れたリンクを報告した場合 (たとえば、ツリー オブジェクトに存在しない BLOB が含まれている場合)、含まれているオブジェクトと参照されているオブジェクトの両方が 40 進のオブジェクト名で報告されました。
コマンドは、--name-objects既存の参照 (例: " HEAD~24^2:file.txt") から含まれるオブジェクトへのパスを表示する " " オプションを学習しました。


3 年後、git fsck は Git 2.25 (2020 年第 1 四半期) でリファクタリングされています。「git fsck」で使用されるオブジェクトの解析と低レベルのオブジェクト アクセスに関して長年にわたって蓄積された厄介なコードとロジックがクリーンアップされました。

これにより、fsck がエントリを装飾する方法が修正されます。

B2F2039のコミット、C5B4269のコミット、 103FB6Dのコミット、コミットF648EE7CC57900コミットコミット7854399B8B00F1コミットコミット6DA40B2、コミットメントF597937コミットメント82CBC441コミットメント82.FCBC41コミットメント参照してください2175a0cコミット ec65231コミット 1de6007コミット 78d5014コミット 12736d2コミット c78fe00 (2019 年 10 月 18 日)、コミット 228c78f (2019 年 10 月 25 日) by Jeff King ( peff)
( 2019 年 12 月 1 日にコミット 0e07c1cJunio C Hamanoによってマージされました)gitster

fsck: オブジェクト名コードを統一

署名者: Jeff King

コミット90cf590f53 (" fsck: オプションで壊れたリンクに関するより役立つ情報を表示する"、2016-07-17、Git v2.10.0-rc0 --バッチ #7に記載されているマージ) は、名前でオブジェクトを装飾するためのシステムを追加しました。コードは(初期名を与える) と(オブジェクト グラフを走査するときに名前に追加する) に分割されます。 これにより、一部の重複が発生し、両方のサイトがほぼ同一の機能を持っています (違いは、 のサイトではバッファの循環配列を使用して単一の で複数の呼び出しを許可することです)。builtin/fsck.cfsck.c
describe_object()builtin/fsck.cprintf

object_nameに統一されたAPI を提供しましょうfsck

これにより、重複をなくし、インターフェースの境界をより明確にすることができます (これにより、将来のパッチで実装をさらにリファクタリングできるようになります)。

多くの呼び出し元を少し短くするために静的グローバルに依存しているため、新しい API の薄いラッパーとしてdescribe_object()残します。builtin/fsck.c

また、裸のadd_decoration()呼び出しを に変換builtin/fsck.cしますput_object_name()

これにより、2 つの小さなバグが修正されます。

  1. 私たちはたくさんの小さなひもを漏らします。add_decoration() には後一勝のアプローチがあります。装飾を新しい文字列に更新し、古い文字列を返します。しかし、戻り値を無視して、古い文字列をリークします。
    reflog を見るので、これは非常に一般的なトリガーです: ref の先端は、実際の ref と最新の reflog エントリの両方を見ることによって記述されます。
    そのため、常にこれらの文字列の 1 つをリークすることになります。

  2. ラスト ワン ウィン アプローチでは、お粗末な名前が付けられます。
    たとえば、最初にすべての参照を調べ、次にすべての参照ログを調べます。
    そのため、" " を表示するのではなく、" refs/heads/master" で上書きする可能性がありますHEAD@{12345678}
    通常は、見つけた最初の名前を使用する方が適切です。

実際、t1450 のテストでは、この醜いHEAD@{}名前が想定されています。このパッチの後、の先着順セマンティクスの
使用に切り替え、より人間に優しい " " を出力します (それに応じてテストが更新されます)。fsck_put_object_name()refs/tags/julius

于 2016-07-26T19:02:18.210 に答える