GIT VISUALIZER

git reset

コミット履歴を巻き戻すコマンド。--soft / --mixed / --hard で巻き戻しの深さを選べます。

HEAD のみ移動— 変更は staged のまま残る(最も安全)
初期状態
git reset 実行前の状態
コミットが2つある状態です。最初の commit 1(c1a2b3c)で README.md を追加し、次の commit 2(d4e5f6a)で app.ts を追加しました。HEAD(現在位置)は commit 2 を指しています。git log では新しい順に上から表示されます。これから git reset を使って、HEAD を1つ前の commit 1 に戻します。モードによって「何がどこまで巻き戻るか」が変わります。
ステップ制御
進捗1 / 3
リセット範囲
HEAD / Refsリセット
Index変更なし
Working Dir変更なし
GIT RESET 可視化STEP 1
CODE VIEW
$ git log --oneline
d4e5f6a (HEAD -> main) Add app.ts ← 今ここ(最新)
c1a2b3c Initial commit ← 1つ前
 
# コミットの流れ(古い → 新しい):
# c1a2b3c → d4e5f6a
# (commit 1) (commit 2) ← HEAD はここ
 
# commit 1: README.md だけのプロジェクト
# commit 2: app.ts を追加した
 
# これから git reset で commit 1 に戻します
Working Directory
Index(ステージングエリア)
blob(ファイル内容)
tree(ディレクトリ構造)
commit(コミット)
.git/refs/(ブランチ参照)
削除される要素
GIT RESET ステップログ
1git reset 実行前の状態
2git reset --soft を実行
3git reset --soft 完了
解説

📌
git reset とは

git reset は、コミットを取り消して過去の状態に巻き戻すコマンドです。 タイムマシンのように「あの時点に戻りたい」というときに使います。

git reset の特徴は、巻き戻しの「深さ」を3段階で選べることです。 HEAD だけ戻すのか、Index も戻すのか、Working Directory まで全部戻すのか — この違いが--soft--mixed--hard の3つのモードです。

上のモード切り替えボタンで、それぞれの違いをステップごとに確認してみてください。

⚙️
git reset の内部処理

git reset は内部で最大3つの処理を順番に実行します。モードによって「どこで止まるか」が変わります。

1
HEAD(ブランチポインタ)を移動する
.git/refs/heads/main のハッシュを指定したコミットに書き換えます。--soft はここで止まります。
--soft / --mixed / --hard
2
Index を指定コミットの状態に合わせる
ステージングエリアの内容を、指定コミットの tree に合わせてリセットします。--mixed はここで止まります。
--mixed / --hard
3
Working Directory を指定コミットに合わせる
ディスク上のファイルを書き換えます。コミットされていない変更は完全に消失します。--hard のみ実行します。
--hard のみ

🔄
3つのモードの違い

.git/refs/
(ブランチポインタ)
.git/indexWorking Dir
--softポインタ移動変更なし変更なし
--mixedポインタ移動リセット変更なし
--hardポインタ移動リセットリセット
--softコミットだけやり直したいとき。変更は staged のまま残るので、すぐに git commit できる。コミットメッセージを変えたい、複数コミットをまとめたいときに便利。
--mixedデフォルトのモード。変更は Working Directory に残るが unstaged になる。git add からやり直したいときに使う。
--hard完全に巻き戻す。変更はすべて消える。「この作業は全部なかったことにしたい」ときに使う。破壊的なので注意。

🧩
3つの領域

git reset を理解するには、Git が管理する3つの領域を知る必要があります。 reset はこの3つの領域を「右から左」に順番にリセットしていきます。

Working Directory(作業ディレクトリ)
ディスク上の実際のファイル。エディタで開いて編集するのはここです。--hard だけがこの領域をリセットします。リセットされると、コミットされていない変更は完全に消えます。
.git/index(ステージングエリア)
git add で登録された「次のコミットに含める予定のファイル一覧」です。--mixed と --hard がこの領域をリセットします。リセットされると、ファイルは unstaged(git add されていない)状態に戻ります。
.git/refs/(ブランチポインタ)
ブランチが「どのコミットを指しているか」を記録するファイルです。すべてのモードがこのポインタを移動します。例えば .git/refs/heads/main に書かれたハッシュが、指定コミットのハッシュに書き換わります。HEAD 自体は常に refs/heads/main を参照しており変化しません。

💻
コマンドとオプション

git reset --soft [コミット]HEAD のみ移動。変更は staged のまま残る
git reset [コミット]--mixed がデフォルト。HEAD + Index をリセット
git reset --mixed [コミット]上と同じ。--mixed を明示的に指定
git reset --hard [コミット]HEAD + Index + WD を全リセット(破壊的)
git reset HEAD~1直前のコミットを1つ取り消す(HEAD~2 で2つ)
git reset HEAD [ファイル]特定ファイルだけ unstage する(git add の取り消し)

💾
なぜ --hard でも .git/objects/ は消えないのか

git reset は「参照(ポインタ)を動かす」コマンドであり、オブジェクトを削除するコマンドではありません。 --hard でも操作対象は .git/refs/、.git/index、Working Directory の3つだけで、.git/objects/ には一切触りません。

.git/objects/ の設計思想

.git/objects/ は Git の全データ(ファイル内容・ディレクトリ構造・コミット履歴)を保存する場所です。 このストアは追記専用(append-only)で設計されており、blob、tree、commit は一度作られたら通常の Git 操作では削除されません。 これが Git の安全性の土台になっています。

git reset --hard 後の .git/objects/ の状態
bloba9f3b7eREADME.mdmain から参照あり
blobe4f5a6bapp.tsどこからも参照なし(孤立)
treet4e5f6aroot treecommit d4e5f6a から参照
commitd4e5f6aAdd app.tsブランチ参照なし(孤立)
commitc1a2b3cInitial commitmain から参照あり
# 孤立オブジェクトが消えるのは git gc だけ
$ git gc --prune=now
 
# デフォルトでは 90 日間は reflog が保持するため
# git gc を手動実行しても消えない
$ git reflog expire --expire=now --all
$ git gc --prune=now
# ↑ この2つを両方実行して初めて物理削除される

注意: --hard で消えた Working Directory の変更(コミットされていない編集内容)は .git/objects/ にも存在しないため、復元できません。復元できるのは、過去にコミットされたことがあるデータだけです。

⚠️
よくある失敗と対処法

--hard で消してしまった変更を復元したい

--hard で消えたコミットは、実は .git/objects/ にまだ残っています。git reflog で過去の HEAD の移動履歴を確認し、消えたコミットのハッシュを見つけましょう。

# reflog で消えたコミットを探す
$ git reflog
c1a2b3c HEAD@{0}: reset: moving to c1a2b3c
d4e5f6a HEAD@{1}: commit: Add app.ts
 
# 見つけたハッシュで復元
$ git reset --hard d4e5f6a

ただし、コミットされていないファイルの変更(Working Directory の変更)は reflog でも復元できません。

push 済みのコミットを reset してしまった

他の人と共有しているブランチで reset すると、履歴の不一致が起きます。 push 済みのコミットを取り消すには git revert を使いましょう。 revert は「取り消すコミット」を新しいコミットとして追加するので、履歴が壊れません。

# push 済みコミットの取り消しには revert を使う
$ git revert [コミットハッシュ]
 
# reset + force push は履歴を壊すので避ける
# git push --force ← 共有ブランチでは危険!
--soft と --mixed を間違えた

--mixed(デフォルト)で reset した後に「staged のままにしたかった」と気づいた場合は、git add . で再ステージすれば --soft と同じ状態になります。 逆に --soft で reset した後に unstage したい場合は git reset HEAD(ファイル指定なし)で Index だけリセットできます。

関連コンテンツ