まず、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
オブジェクトを探したい。tree
2番目の後の状態を説明するオブジェクトも必要です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 -u
、git commit -a
追跡されたファイルへのすべての変更をステージングする、です。新しいファイルを追跡するには、明示的に指定することをお勧めします。