↩️
git reset/restore/checkout の違いを完全理解する
Gitで戻りたい・戻したいときに使用する以下のコマンドの違いを一覧表で説明します。
git reset
git restore
git checkout
- (
git switch --detach
)
TL;DR
- ブランチの歴史を改変したい →
git reset
- 手元のファイルだけ変更したい →
git restore
-
git checkout
はgit 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
Discussion