↩️

git reset/restore/checkout の違いを完全理解する

2025/03/09に公開

Gitで戻りたい・戻したいときに使用する以下のコマンドの違いを一覧表で説明します。

  • git reset
  • git restore
  • git checkout
  • (git switch --detach)

TL;DR

  • ブランチの歴史を改変したい → git reset
  • 手元のファイルだけ変更したい → git restore
  • git checkoutgit restore と同じことができます。ただし機能が多く複雑なので初学者にはおすすめしません

前提知識

  • 作業ツリー(作業ディレクトリ): 手元のファイル
  • インデックス(ステージング領域): git add したファイル
  • ブランチ: あるコミットへの参照
  • HEAD: 今いるブランチへの参照


git reset 時のイメージ図[1]

過去のコミットに戻る・戻す

過去の(特定の)コミットに戻りたい・戻したいときのコマンドの違いを説明します

コマンドを実行したとき、作業ツリー、インデックス、ブランチ、HEADが変化するかどうかを以下の表にまとめます。

コマンド 作業ツリー インデックス ブランチ HEAD
git reset --hard <commit> ↩️ ↩️ ↩️ (↩️)
git reset <commit> - ↩️ ↩️ (↩️)
git reset --soft <commit> - - ↩️ (↩️)
git restore -s <commit> . ↩️ - - -
git restore -s <commit> --staged . - ↩️ - -
git restore -s <commit> --staged --worktree . ↩️ ↩️ - -
git switch --detach <commit> ↩️ ↩️ - ↩️
git checkout <commit> . ↩️ ↩️ - -
git checkout <commit> ↩️ ↩️ - ↩️

凡例:

  • ↩️: 作業ツリー・インデックスは、指定したコミットの状態になります。ブランチは、指定したコミットを参照するようになります。HEADは、detached HEADとして指定したコミットを参照するようになります
  • (↩️): ブランチの参照先コミットが変わるため、そのブランチを参照しているHEADも一緒に移動します

ここで、-s <commit>--source=<commit> の省略記法です

用途別に使えそうなコマンドをピックアップして、以下の表に示します。

目的・用途 コマンド 備考
過去のコミットに戻りたい(全部戻したい) git reset --hard <commit> 作業中の変更や最新のコミットは確認なく消える[2]ため要注意
コミットをやり直したい(手元のファイルはそのままで、ブランチだけ戻したい) git reset <commit> 直前コミットの修正なら git commit --amend も検討
過去のコミットを復元したい/手元で見たい git restore -s <commit> . . の代わりにパスを書いて特定ファイルだけ復元もできます

「過去のコミットの復元」にはよく git checkout が使用されてきましたが、意図せずdetached HEADになると少し危険なため、HEADの動かない git restore を使うか、意識的に git switch --detach を使うといった具合に、checkout を代替する新コマンド(restore / switch)を使っていくのが良いのだろうと思います。

コミット前の変更を戻す

ここまでは過去のコミットを参照したいときのコマンドを紹介しましたが、ここからはコミット前の変更を戻す(破棄する)コマンドを紹介します。こちらの方が日常的に使うと思います。

コマンドを実行したとき、作業ツリー、インデックスが変化するかどうかを以下の表にまとめます。

コマンド 作業ツリー インデックス
git restore . ↩️* -
git restore -s HEAD . ↩️ -
git restore --staged . - ↩️
git restore --staged --worktree . ↩️ ↩️
git reset - ↩️
git reset --hard ↩️ ↩️
git checkout . ↩️* -
git checkout HEAD . ↩️ ↩️

凡例:

  • ↩️: HEADの状態になります
  • ↩️*: インデックスの状態になります

いずれのコマンドも確認なく実行される(変更が消える) ため要注意です。

用途別にコマンドを挙げると、以下のようになります。いろいろと書きましたが、結局これだけ覚えておけば良いと思います。

目的・用途 コマンド 備考
ステージしていない変更を破棄したい git restore . . の代わりにパスを書いて特定ファイルだけ破棄もできます
アンステージしたい(git add を取り消したい) git restore --staged . 同上

ちなみに、これらのコマンドは git status を実行すると提案されるコマンドですね。

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

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:   bar.txt

参考

脚注
  1. 図解 Git ↩︎

  2. 厳密には、コミット済みの変更であれば見えなくなっただけで、取り戻すことができます ↩︎

Discussion