Gitの“やっちまった”に効く!reflogとresetで履歴を救う方法【Git】

  • LINEで送る
Gitのやっちまったに効くreflogとresetで履歴を救う方法

 Gitで作業していると、うっかり reset --hard してしまったり、意図せずコミットを消してしまったりすることは珍しくありません。そんなときに覚えておきたいのが reflogreset の活用術です。この記事では、Gitの履歴を救うための具体的なパターンと対処法を紹介します。

よくあるハマりパターン

  • git reset --hard で大事なコミットが消えた
    ステージや作業ツリーをすべて指定したコミットの状態に戻す reset --hard。便利な反面、直前のコミットをうっかり飛ばしてしまい、意図しないロールバックが発生しがちです。
  • git commit --amend で前のコミットを上書きしてしまった
    直前のコミットを修正できる --amend は便利ですが、過去のコミットを上書きしてしまい、あとで「戻したい」と思ったときに困るケースがあります。
  • git stash pop のコンフリクト後に stash 内容が消えた
    stash pop は適用と同時に stash を削除します。コンフリクトが発生しても削除は実行されるため、解決前に元の内容を失ってしまう危険があります。
  • git rebase で履歴が意図せず書き換えられた
    コミット履歴を整理するために使われる rebase ですが、やり方を誤ると複数のコミットが消えてしまったり、履歴が複雑になって戻せなくなることがあります。
  • git checkout . で作業中の変更がすべて消えた
    ワーキングツリーのすべての変更を破棄するこのコマンドは、保存していなかった修正を一瞬で失う危険があります。

 これらの失敗は、絶対に戻せないミスではありません。これから説明するreflogresetコマンドで十分リカバリ可能です。焦らず落ち着いて復旧作業を行いましょう。

▶︎ git reflog : HEADの移動履歴の閲覧コマンド

 git reflog は、HEADの移動履歴を閲覧するコマンドです。Gitで作業をしていると、resetrebasecheckout などによってブランチの先頭(HEAD※1)の位置が頻繁に移動します。これらの操作は、git log では見えなくなることがありますが、reflog はそのすべてを記録しており、「どのタイミングで、どのコミットに移動したか」を正確に辿ることができます。

 このため、操作ミスによって履歴が壊れたように見えても、reflog を使えば「どこに戻ればよかったのか」「いつ間違ったのか」といったタイミングを特定する手がかりになります。特に reset --hardrebase のような破壊的な操作を行った後に、元の状態に戻したい場合に非常に頼りになるコマンドです。

💡 補足:HEADとは?
Gitにおける HEAD は「今現在、自分が作業している場所(コミット)」を指すポインタです。基本的には現在のブランチの最新コミットを指していますが、checkoutreset によってこの位置が動きます。HEAD がどこを指しているかによって、次に行われるコミットの位置も変わります。

基本構文

git reflog

reflogの出力例

% git reflog
d0c71f3 (HEAD -> main) HEAD@{0}: commit (amend): 3回目のcommitと4回目の編集
adaf5d2 HEAD@{1}: rebase (finish): returning to refs/heads/main
adaf5d2 HEAD@{2}: rebase (squash): 3回目のcommit
a335901 HEAD@{3}: rebase (reword): 3回目のcommit
ffe0d9b HEAD@{4}: rebase: fast-forward
2400efa HEAD@{5}: rebase (start): checkout HEAD~4
53d46bb HEAD@{6}: commit: 5回目のcommit
fadce32 HEAD@{7}: commit: 4回目のcommit
ffe0d9b HEAD@{8}: commit: 3回目のcommit
2400efa HEAD@{9}: commit: 2回目のcommit
eb84fe0 HEAD@{10}: commit (initial): 1回目のcommit
% 

 一番上の行が最新のHEADの位置です。この例では、5回commitをした後、rebaseコマンドでcommit履歴を編集しています。

 このように HEAD@{0} は現在の状態、HEAD@{1} はその1つ前の状態、というようにHEADの移動履歴が記録されています。各操作に応じて、「commit」「reset」「checkout」「merge」などのアクション名とともに、どのような動きがあったかが表示されます。

▶︎ git reset :指定した履歴まで戻るコマンド

 reflog で目的の過去状態を確認できたら、その履歴のポイントに戻るために使うのが git reset コマンドです。reset は Git の中でも非常に強力な履歴操作コマンドで、作業ディレクトリ、インデックス(ステージ)、HEAD の位置を意図した状態に戻すことができます。

git reset の3つのモード

git reset には以下の3種類のオプションがあり、それぞれ影響範囲が異なります:

  • --soft
    • HEAD だけを指定した位置に戻す
    • インデックス(ステージ)や作業ツリーはそのまま
    • 使いどころ:履歴だけ巻き戻して、変更内容は残したいとき
  • --mixed(デフォルト):
    • HEAD とインデックスを指定した位置に戻す
    • 作業ツリーはそのまま
    • 使いどころ:コミットとステージの状態を一度クリアにしたいとき
  • --hard
    • HEAD、インデックス、作業ツリーすべてを完全に巻き戻す
    • 使いどころ:完全にその時点の状態に戻したいとき(破壊的なので慎重に!)

使用例

 実際に、先ほどreflogで確認した履歴を遡って、rebaseのコマンドが実行される前まで戻ってみます。「53d46bb HEAD@{6}: commit: 5回目のcommit」このcommitまで戻ってみます。そのためコマンドは下記になります。

git reset --hard HEAD@{6}
# rebaseする前まで戻る
 % git reset --hard HEAD@{6}
HEAD is now at 53d46bb 5回目のcommit
tamon1028@MaedaTamonMacBook git-sample % git reflog               
53d46bb (HEAD -> main) HEAD@{0}: reset: moving to HEAD@{6}
d0c71f3 HEAD@{1}: commit (amend): 3回目のcommitと4回目の編集
adaf5d2 HEAD@{2}: rebase (finish): returning to refs/heads/main
adaf5d2 HEAD@{3}: rebase (squash): 3回目のcommit
a335901 HEAD@{4}: rebase (reword): 3回目のcommit
ffe0d9b HEAD@{5}: rebase: fast-forward
2400efa HEAD@{6}: rebase (start): checkout HEAD~4
53d46bb (HEAD -> main) HEAD@{7}: commit: 5回目のcommit
fadce32 HEAD@{8}: commit: 4回目のcommit
ffe0d9b HEAD@{9}: commit: 3回目のcommit
2400efa HEAD@{10}: commit: 2回目のcommit
eb84fe0 HEAD@{11}: commit (initial): 1回目のcommit

# commit履歴を確認
 % git log --oneline
53d46bb (HEAD -> main) 5回目のcommit
fadce32 4回目のcommit
ffe0d9b 3回目のcommit
2400efa 2回目のcommit
eb84fe0 1回目のcommit

 git logでcommit履歴を確認したところ、rebaseコマンドがなかったことになり、commitの数も5回で終了しています。このように書くことで、reflog で記録された「指定した状態」に完全に戻すことができます。

他にも、変更を保持したい場合には次のように使えます:

git reset --soft HEAD@{6}

 このコマンドで、HEAD は過去のコミットに戻りますが、変更内容はステージに残ったままになります。続けて git commit を実行すれば再コミットが可能です。

⚠️ 注意点

  • --hard を使うと作業ツリーの変更が完全に失われるため、事前に git stash を使って退避しておくことを強く推奨します。
  • reset の対象はあくまで「現在のブランチ」に対してのみです。他ブランチに影響はありません。

 このように、reflog × reset の組み合わせは、「過去の状態に戻りたい」というニーズに応える最も基本で確実な手段です。

ハマったときの復旧フロー

 Gitで「やってしまった!」と気づいたとき、パニックにならずに以下の手順を踏むことで、状況を冷静に整理し、安全に復旧できます。

  1. git status で現在の状態を確認
    まずは今の作業ディレクトリとインデックスの状態を確認します。未コミットの変更や、どのブランチにいるかを把握しておくことで、以降の対応方針が決まります。
  2. git log / git reflog で履歴を調査
    git log では通常のコミット履歴を確認できますが、失われたように見えるコミットや移動履歴を含めて確認するには git reflog が重要です。操作ごとにどのコミットへHEADが移動したかが記録されているので、間違えたタイミングを特定できます。
  3. 戻したい状態の HEAD@{n} を見つける
    reflog を確認し、望ましい状態にいたタイミング(例:HEAD@{3})を探します。コメント欄には操作の種類(例:commitreset)が記載されており、状況の見極めに役立ちます。
  4. git reset を使ってHEADを戻す
    状況に応じて --soft(変更を残す)、--mixed(インデックスだけクリア)、--hard(すべて巻き戻す)のいずれかを選んで reset します。git reset --hard HEAD@{3}コミットや作業ツリーの状態も含めて、過去の任意の地点に戻すことが可能です。
  5. 作業内容を退避したい場合は git stash を活用
    もし変更中のファイルを保持しておきたいなら、reset や他の操作の前に git stash を使って一時的に退避させておきましょう。こうすることで、リスクを最小限に抑えながら安全に操作できます。
  6. 必要であれば一時ブランチを切っておく
    不安な場合は、reflog で戻したいポイントをブランチ化してから確認するのも手です:git branch recovery HEAD@{3}これで現在の作業ブランチに影響を与えず、復旧作業を試すことができます。

ケース別対応まとめ

トラブル内容対応コマンドHEAD の移動履歴から復旧可能
reset –hard で巻き戻したgit refloggit reset --hard HEAD@{X}HEAD の移動履歴から復旧可能
rebase で消えたコミットgit refloggit branch tmp HEAD@{X}一時ブランチを切って確認
stash pop で消えたgit fsck --lost-found消えたように見えても復旧可能なことがある
checkout . で変更を失ったgit checkout HEAD -- ファイル名ファイル単位での復元が可能

💡 補足:git fsck とは?
 git fsck は、Git の内部オブジェクトの整合性を確認するためのコマンドです。オプション --lost-found を付けることで、通常の履歴からは参照されていない「孤立したオブジェクト」(例えば削除されたけどまだ残っているコミットやファイルなど)を .git/lost-found ディレクトリに一覧表示できます。誤って削除した変更が復元できる可能性があります。

Gitのリカバリに使えるコマンドまとめ

 とにかく”やっちまった”と思ったら、これらのコマンドで確認してみましょう。必ず解決の糸口が見つかるはずです。

git reflog                     # HEAD の履歴を見る
git reset --hard HEAD@{1}      # 過去の状態に完全に戻す
git reset --soft HEAD@{1}      # ステージングを残して戻す
git checkout HEAD -- file.txt  # 特定ファイルを復元
git stash                      # 作業内容を一時退避
git fsck --lost-found          # 消えたデータの可能性を探る

まとめ

 Gitは履歴操作を誤っても、多くの場合 reflog を使って元に戻すことができます。焦らずに状態を確認し、冷静に履歴をたどることが大切です。普段からこまめにブランチを切る・タグをつけるといった予防策もあわせて心がけましょう


目次

実務で使えるGit講座 ― 初心者から即戦力まで6ステップ TOP

第1部 Gitの導入と基礎知識

  1. Gitとは? なぜ必要か?
  2. Gitのインストールと初期設定
  3. 最初のGit操作:init / clone / status

第2部 基本操作とローカルでの履歴管理

  1. ファイルの変更を記録:add / commit
  2. 履歴の確認と変更の取り消し:log / diff / restore
  3. Gitの仕組みを理解する(ステージングエリアとは?)

第3部 ブランチとマージの基本

  1. ブランチの概念と作り方
  2. マージとコンフリクト解消
  3. Git Flow・開発ブランチ運用の基本

第4部 GitHubを使ったチーム開発

  1. リモート操作:push / pull / fetch
  2. GitHubとプルリクエストの流れ
  3. チーム運用でのルール作り

第5部 実務で差がつく応用操作

  1. 履歴の書き換え:rebase / amend / stash
  2. タグ・リリースとCI/CDの連携
  3. Gitトラブル対応集(reflog / resetハマり対策)

第6部 GitHub Copilotの活用術

  1. GitHub Copilotとは?できること・できないこと

最新の投稿

SNSでもご購読できます。

コメントを残す