10
11

git reset --hardを間違えてしてしまった時の対処法

Last updated at Posted at 2024-08-29

おっと手が滑って...reset --hardしちゃった場合...ありませんか?(あったらえらいこっちゃですが...)

本記事ではgit reset --hardを実行した後の復元方法について,addしていない場合,addした場合,commitした場合のそれぞれについて説明する.

addしていない場合(ワーキングディレクトリのみに変更がある場合):

この状況では,変更は完全に失われる.Gitの機能だけでは復元は不可能である.ファイルシステムの復元ツールを使用する必要があるが,成功の保証はない.

例えばgit statusをしてワーキングエリアとステージングエリアの状態を確認する

git status

すると,example.txtがステージングエリア(インデックス)になく,addされていないことがわかる.

On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   example.txt

この状態でgit reset --hardをする.

git reset --hard

HEAD が1つ前のコミットを指すようになる.

HEAD is now at 1a2b3c4 Previous commit message

この状態でgit statusをすると

git status

ワーキングエリアやステージングエリアにもexamle.txtの変更差分がなくなっていることがわかる.

On branch main
nothing to commit, working tree clean

このようにaddをしずにreset --hard するとどうすることもできないので要注意

commitしてaddした場合(ステージングエリア(インデックス)に変更がある場合):

example.txtをaddして,git statusをしてワーキングエリアやステージングエリアの状態を確認する.

git add example.txt
git status

するとステージングエリアにexample.txtの変更差分が存在することがわかる.

On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   example.txt

この時点でgit reset --hard をすると...

git reset --hard

HEADが1つ前のコミットを指すようになる.

HEAD is now at 1a2b3c4 Previous commit message

この状態でgit statusをすると

git status

ワーキングエリアやステージングエリアにもexamle.txtの変更差分がなくなっていることがわかる.

On branch main
nothing to commit, working tree clean

しかしaddをした場合blobオブジェクトが作成され,どのコミットやタグもそのblobオブジェクトに対して参照を持たない状態になる.そのため参照を持たないblobオブジェクトを探すコマンドが以下である,.

git fsck --lost-found

2d3e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0という参照されていないblobオブジェクトが出力された.

Checking object directories: 100% (256/256), done.
Checking objects: 100% (1234/1234), done.
dangling blob 2d3e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0

中身をgit showするとファイルの内容を見ることができる.

git show 2d3e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0

正しい内容だった場合,該当のblobオブジェクトをaddする.

git add .git/lost-found/other/2d3e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0

今度こそコミットを忘れない.

git commit -m "ふっかーーつ"

git add したファイルはgit reflogで探せないのか

git reflogとは
HEADが移動する操作(commit branch reset)をした際のローカルリポジトリの操作履歴を参照する

結論から言うと,git addしたファイルはgit reflogに残らない.そのため,git reflogでは参照できない.
git reflogは主にHEADの移動履歴を記録する.つまり,以下のような操作が記録される.

  • コミットの作成
  • ブランチの切り替え
  • リセット操作

このようにresetした履歴は残るがaddした履歴は残らないのでgit reflogではaddしたgit オブジェクトを参照できない.

しかし,git addしたファイルはblobオブジェクトとして保存されるのでgit fsckで参照がないblobオブジェクトを参照できる

blobオブジェクトとは
Gitには主に4種類のオブジェクトがある.

  • blob: ファイルの内容
  • tree: ディレクトリ構造
  • commit: コミットの情報
  • tag: タグの情報

commitした場合

コミットをして

git commit -m "New commit"

コミットした際の出力

[main 3f4g5h6] New commit
 1 file changed, 1 insertion(+)

これでリセットをした場合...

$ git reset --hard HEAD~1

HEADhは1つ前のコミットを指している.

HEAD is now at 1a2b3c4 Previous commit message

この場合commitをしている(=HEADを移動した)のでreflogで参照できる操作である.ためreflogでcommitをした操作を探す.

git reflog

するとresetした操作やcommitした操作を参照できるので3f4g5h6がコミットした操作で得ることがわかる.

1a2b3c4 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
3f4g5h6 HEAD@{1}: commit: New commit
1a2b3c4 HEAD@{2}: commit: Previous commit message

ここで3f4g5h6nにresetする.つまりresetしてしまったらresetで復活させることができる.

git reset --hard 3f4g5h6

これでresetをresetできた.

HEAD is now at 3f4g5h6 New commit
10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11