13

インデックスにいくつかのファイルを追加しましたが、誤って。で削除しましたgit reset --hard。それらを回復するにはどうすればよいですか?何が起こったのか:

  1. を使用してすべてのファイルを追加しましたgit add .
  2. それから私はコミットしました
  3. ステータスを確認したところ、追加からのコミットに含まれていないファイルがまだありましたが、これは奇妙でした
  4. 追跡されていないファイルを再度追加しましたが、今回は機能しました
  5. しかし、すべてを1つのコミットにまとめたかったので、コミットした内容をステージング解除する方法を調べました。
  6. 私が使用git reset --hard HEAD^しました—悪い考えです、明らかに、すべてのファイルが削除されました
  7. だからgit reflog私は中断したところを見つけていました
  8. その後git reflog ______、最後のコミットに戻りました。
  9. その後git reset HEAD、コミットのステージングを解除していましたが(最初に実行する必要がありました)、コミット後に追加したファイル(上記を参照)はまだ残っていました。

これらのファイルを元に戻すにはどうすればよいですか?

4

2 に答える 2

23

まず、Git リポジトリの完全なバックアップを作成してください。

ファイルをgit add作成すると、git はこのファイルのコンテンツから blob を作成し、それをオブジェクト データベース ( .git/objects/??/*) に追加します。

コマンドを 1 つずつ見てみましょう。

git add を使用してすべてのファイルを追加しました。

$ git add .

これにより、現在のディレクトリとそのサブディレクトリに含まれるすべてのファイルが Git のオブジェクト データベースに追加されます。ファイルのパターンに一致する追跡.gitignoreされていないファイルは追加されません。ツリー ファイルも書き込まれます。私の答えの最後を見てください。

私はそれからコミットしました

$ git commit -m'added all files'

これにより、新しいコミット オブジェクトがオブジェクト データベースに書き込まれます。このコミットは単一のツリーを参照します。ツリーは、BLOB (ファイル) と他のツリー (サブディレクトリ) を参照します。

ステータスを確認すると、追加からのコミットに含まれていないファイルがまだあり、奇妙なことに

$ git status

これが発生する 2 つのシナリオが考えられます。何かがファイルを変更したか、新しいファイルが背後で追加されました。

追跡されていないファイルを再度追加したところ、今回は機能しました

$ git add .

add手順 1 と同じコマンドをもう一度使用したと仮定します。

しかし、すべてを1回のコミットにしたかったので、コミットしたばかりのものをアンステージする方法を調べました

この回答の最後で、ユーザーが潜在的に危険なreset

私は git reset --hard HEAD^ を使用しました — 明らかに悪い考えで、すべてのファイルが削除されました

$ git reset --hard HEAD^

このコマンドは、現在の作業ツリーとインデックスを正確にコミットHEAD^(最後から 2 番目のコミット) に設定します。つまり、コミットされていないローカルの変更をすべて破棄し、ブランチ ポインターを 1 つコミット分戻します。追跡されていないファイルには触れません。

それで、git reflog を使用して中断した場所を見つけました

$ git reflog

これは、最近チェックアウトされた最後のコミットを示します ( と同じgit reflog HEAD)。ブランチ名を指定すると、このブランチが最近指した最後のコミットが表示されます。

次に、 git reflog __を使用して最後のコミットに戻りました。

これについてはわかりません。git reflog(ほとんど)読み取り専用コマンドであり、コミットに「戻る」ために使用することはできません。HEADブランチ(または)が指すコミットを見つけるためにのみ使用できます。

次に、 git reset HEAD を使用してコミットをステージング解除しましたが(最初に行うべきこと)、コミット後に追加したファイル(上記を参照)はまだ消えていました。$ git リセット HEAD

これはこのコミットをステージング解除しませんが、ステージングされた (ただしコミットされていない) すべての変更をインデックスからステージング解除します。git reset HEAD^もともと(最初のステップ)、 (または)と言いたかったのですが、git reset --mixed HEAD^これにより、作業ツリーはそのまま残りますが、 によって名前が付けられたコミットが指すツリーと一致するようにインデックスが設定されHEAD^ます。


ここで、ファイルを取り戻すには、git fsck --full --unreachable --no-reflog. Git のオブジェクト データベース内のすべてのオブジェクトをスキャンし、到達可能性分析を実行します。blobオブジェクトを探したい。tree2番目の後の状態を説明するオブジェクトも必要ですgit add .

git cat-file -p <object hash>ファイルの内容が出力されるので、正しいオブジェクトがあることを確認できます。BLOB の場合、IO リダイレクトを使用してコンテンツを正しいファイル名に書き込むことができます。ツリーの場合は、git コマンド ( git read-tree) を使用する必要があります。ファイル数が少ない場合は、ファイルに直接書き込む方がよいでしょう。


ここにいくつかのメモ:

最後のコミットにファイルを追加する (またはそのコミット メッセージを編集する) 場合は、単純にgit commit --amend. 基本的にはラッパーgit reset --soft HEAD^ && git commit -c HEAD@{1}です。

また、 を使用することはほとんど良い考えではありませんgit add .。通常、新しいリポジトリを作成するときに初めて使用するだけです。より良い代替手段はgit add -ugit commit -a追跡されたファイルへのすべての変更をステージングする、です。新しいファイルを追跡するには、明示的に指定することをお勧めします。

于 2012-05-28T11:29:52.293 に答える
15

同様の問題が発生しましたが、リポジトリにぶら下がっているブロブとツリーがたくさんあったためgrep、すべてのぶら下がっているブロブの出力でフィルタリングし、一致するものを印刷することになりました。インデックス${UNIQUE_CODE}にあるファイルに固有のコードがあるとすると、これにより、探しているBLOBのハッシュが得られます。

for b in $(git fsck --lost-found | grep blob | awk '{print $3}'); do git cat-file -p $b | grep -q ${UNIQUE_CODE} && echo $b; done
于 2013-02-20T19:18:42.003 に答える