マガジン

AIに任せた作業で消えたコミットを、reflogで探して復元する手順

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

ひもから外れた木札をクリップで確保する手元
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

AIに「履歴を整理して」と頼んだあと、git log から数個のコミットが消えていた。こういうときは、まず何も実行せず git reflog を開いてください。コミットされていた内容は、多くの場合ローカルリポジトリに残っています。 大まかな流れは次の3つです。 1. git reflog で、消える直前の状態の行を探し、コミットIDを控える 2. git branch rescue/before-reset <コミットID> で、そのコミットに名前を付けて確保する 3. 内容を確認してから、元のブランチをその位置へ戻す Git公式ドキュメントによると、reflogはローカルリポジトリで、ブランチなどの参照の先端がいつ更新されたかを記録します(git-reflog)。reset --hard でブランチが後ろへ動いても、動く前の位置は記録に残ります。ただし、コミットしていなかった変更は戻せないことがあります。この点は後半で整理します。

この記事の目次
  1. 最初にやること:これ以上、状態を動かさない
  2. reflogの読み方
  3. 復元コマンドの手順
  4. 復元できない・難しいケースの見分け方
  5. AIに渡す依頼文
  6. 人が確認すること

最初にやること:これ以上、状態を動かさない

AIのエージェントを使っている場合は、その実行を止めてください。以降のコマンドは自分で実行します。理由は、reset や checkout、commit を重ねるほど、reflogの行が増えて目的の行を見つけにくくなるためです。

次の2つで現状を確認します。

bash
git status
git reflog -n 20

git reflog は git log -g --abbrev-commit --pretty=oneline の別名で、ログ向けオプションも受け付けると公式に書かれています。-n 20 は直近20件に表示を絞ります。目的の操作が見つからなければ、件数を増やすか、オプションなしで実行してください(git-reflog、git-log)。

reflogの読み方

次は説明用の例です。実際のリポジトリの出力ではありません。

a1b2c3d HEAD@{0}: reset: moving to HEAD~3
e4f5a6b HEAD@{1}: commit: ログイン画面のエラー表示を追加
9c8d7e6 HEAD@{2}: commit: 入力チェックを関数に分離
5f4e3d2 HEAD@{3}: commit: ログインAPIを呼び出す処理を追加
a1b2c3d HEAD@{4}: checkout: moving from main to feature/login
  • 一番上の HEAD@{0} が現在の位置です。reset: moving to HEAD~3 は、3世代前のコミットへ戻す操作を示します。実行したのがAIか人かは、この行だけでは分かりません。
  • 戻したいのは、その1行下の HEAD@{1} です。reset の直前に、ブランチが指していた位置です。
  • 行頭のコミットIDを控えます。HEAD@{1} と書いても指定できますが、操作を重ねると番号がずれます。IDを書き写すほうが安全です。

行の種類は、commit:、reset:、checkout:、rebase 系、merge などの動作名で見分けます。rebase (finish) などが並んでいるなら、AIがrebaseを実行した可能性があります。その場合も探すのは、開始直前の行のIDです。

復元コマンドの手順

1. まず新しいブランチで確保する

bash
git branch rescue/before-reset e4f5a6b
git log --oneline -5 rescue/before-reset

git branch で名前を付けるだけなので、作業ツリーは変わりません。ブランチ名が付けば、あとでreflogの期限が切れても、そのブランチから到達できるコミットは保持されます。確保だけはすぐ済ませてください。

2. 元のブランチを戻す

rescue/before-reset の内容が期待どおりなら、元のブランチを移します。先に git status で、未コミットの変更がないことを確認してください。reset --hard は作業ツリーとインデックスを指定コミットの内容で上書きし、未追跡ファイルを上書きすることもあると、公式に書かれています(git-reset)。

bash
git switch feature/login
git reset --hard rescue/before-reset

公式によると、コミットを指定してブランチを動かす reset は、操作前の先端を ORIG_HEAD に保存します。その直後で、ORIG_HEAD が戻したいコミットを指していれば、git reset --hard ORIG_HEAD でも戻せます。ただし、reset後に他の操作を重ねると、ORIG_HEADの位置が変わる可能性があります。迷ったらreflogのIDを使うほうが確実です。

3. ブランチを削除されたとき

git branch -D で消された場合は、HEADのreflogから探します。ブランチを削除すると、そのブランチのreflogも削除されます(git-branch)。HEADのreflogは切り替え操作も記録するため、ブランチを離れた記録を探します。

bash
git reflog

checkout: moving from feature/login to main の行が見つかったら、その1行下(古い側)のIDを候補にします。切り替えの行頭は移動先のIDです。最後にそのブランチを離れた記録かを確認し、git show <候補のID> で内容を調べてから、そのIDでブランチを作り直します。切り替え後に別の操作で先端が変更されていた場合や、古い記録が失われている場合は、この方法で削除直前の先端を特定できるとは限りません。

bash
git branch feature/login e4f5a6b

復元できない・難しいケースの見分け方

下の表は、公式ドキュメントの記述と、Gitの一般的な動作から整理した判断表です。

  • コミット済みのコミットを reset --hard で外した、reflogで戻せるか:戻せる可能性が高い、次の手:上記の手順1〜2
  • branch -D でブランチを削除した、reflogで戻せるか:HEADのreflogに記録があれば戻せる、次の手:手順3
  • 一度もコミットしていない変更を reset --hard や checkout . で消した、reflogで戻せるか:reflogには記録されない、次の手:git add 済みなら、次節の fsck で探せる場合がある。未追跡ファイルの変更は、エディタの履歴やバックアップが頼り
  • git clean で未追跡ファイルを消した、reflogで戻せるか:reflogでは戻せない、次の手:エディタの履歴やバックアップを確認する(git-clean)
  • git stash drop で退避を消した、reflogで戻せるか:reflogでは戻せない、次の手:git fsck --unreachable で探す(git-stash)
  • 別のPCや別のcloneで作業していた、reflogで戻せるか:そのcloneのreflogにしかない、次の手:作業した場所で確認する
  • リモートに push 済み、reflogで戻せるか:リモートのブランチなどから対象コミットに到達できれば可、次の手:リモート名が origin なら、git fetch origin 後、origin/ブランチ名 から探す。削除や強制pushで失われている場合は保証されない(git-fetch)
  • 長期間たった、または gc 実行後、reflogで戻せるか:難しい、次の手:次節を参照

reflogの保持期間は、公式の既定値で gc.reflogExpire が90日、gc.reflogExpireUnreachable が30日です。また、git gc は、ブランチ・タグ・reflogなどから参照されなくなったオブジェクトのうち、更新時刻が既定で2週間より古いものを削除対象にします。コミットが履歴から外れて2週間たつと必ず消える、という意味ではありません(git-gc)。設定は環境ごとに変えられるため、この日数は目安です。AIが git gc --prune=now や git reflog expire を実行していた場合、救えない可能性があります。

reflogにも出てこないとき

git fsck --lost-found で、どの参照からも使われていない「ダングリング」オブジェクトを .git/lost-found/ に書き出せます。コミットは commit/、それ以外は other/ に分けられます。reflogだけが参照しているコミットまで到達不能として調べたい場合は、--no-reflogs を付けます(git-fsck)。

bash
git fsck --lost-found
git show <表示されたID>

候補が多く出るので、コミットなら git show でコミットメッセージや差分を見て、目的のものを選び、手順1と同様に新しいブランチで確保します。git add 済みの内容がblobとして残っていた場合は、ファイル内容を確認できますが、元のファイル名やコミット履歴まで戻せるとは限りません。これは最後の手段です。見つかる保証はありません。

AIに渡す依頼文

reflogの読み取りをAIに手伝わせる場合は、実行までは任せず、コマンド案と理由だけを出してもらうと安全です。次は、そのまま使える依頼文のひな形です。

Gitで、履歴が消えたように見えます。調査と復元の手順を考えてください。

【条件】
- あなたはコマンドを実行せず、私が実行します
- 履歴や作業ツリーを書き換えるコマンド(reset --hard, clean, gc, checkout . など)は、
  最後の手段としてだけ案を出し、先に「新しいブランチで確保する」案を出してください
- 各コマンドについて、何が変わるか・変わらないかを一行で説明してください

【状況】
- 起きたこと:(例)AIに「履歴を整理して」と頼んだ後、feature/login のコミットが3つ消えた
- 未コミットの変更:(あり / なし / 不明)
- 次の出力を貼ります(社内名・秘密情報は伏せてあります)

(git status の出力)
(git reflog -n 30 の出力)

【知りたいこと】
1. 消える直前の状態はどの行か、根拠つきで
2. 確保用ブランチを作るコマンド
3. この状況で復元できない可能性があるもの

貼る前に、コミットメッセージにお客様名、社内のURL、トークンなどが入っていないか確認してください。必要なら「顧客A」のような仮の名前に置き換えます。

人が確認すること

AIの答えを実行する前に、次の3点は自分の目で見てください。

  • 選んだIDで git log --oneline rescue/before-reset を実行し、消えたはずのコミットメッセージが並んでいるか
  • git diff --stat 現在のブランチ rescue/before-reset で、戻すと何が変わるか
  • 共有ブランチなら、戻す前にチームへ連絡したか。公式のreset解説も、すでに他の人へ渡したコミットを消す操作には注意を促しています

確保用ブランチは、動作確認が済むまで消さずに残してください。

出典・参考資料