バグがどこで混入したのか調べたい時など、一時的に過去のコミットに戻って作業したい場合があります。
その場合は次の checkout コマンドを使います。

一時的に過去のコミットに戻る:
git checkout <コミット>

※ 移動先の HEAD は「detached HEAD」という使い捨ての HEAD となります。それにより本来の HEAD に影響を与えずにいろいろ実験することが可能になっています。

ところが、上の checkout コマンドはワーキングツリーとインデックスと HEAD の内容が一致していないと実行することが出来ません。
例えば前のページの状態16ではワーキングツリーと HEAD の hoge.txt の内容が異なっているのでコマンドを実行できません。
そういう場合は次の様に stash 機能を使ってワーキングツリーとインデックスの内容を一時的に保存してから checkout します。

一時的に過去のコミットに戻る(stash を使う場合):

ワーキングツリーとインデックスの内容を stash に一時保存: git stash
stash の中を確認: git stash list
対象コミットのハッシュ値を調べる: git log
過去のコミットに戻る: git checkout <コミット>
ちゃんと過去に戻れたか確認: git log --all --oneline

例えば状態16から HEAD~2 に戻った状態が以下の状態17となります。
ワーキングツリーとインデックスの内容が元の状態 16 における HEAD~2 の内容に置き換わっていることに注目して下さい。
また元の状態 16 におけるワーキングツリーとインデックスの内容は stash に一時保存され、HEAD は detached HEAD になっています。


状態 17


ワーキングツリー
stash に一時保存されたワーキングツリー
hoge.txt
a
     
hoge.txt
ab
piyo.txt
A


インデックス
stash に一時保存されたインデックス
hoge.txt
ab
     
hoge.txt
ab
piyo.txt
A


ローカルリポジトリ「gitlocal」
本来のHEAD
hoge.txt
ab
"piyo.txtを削除(S16)"
 
hoge.txt
ab
piyo.txt
AB
"piyo.txtを更新(S9)"
(detached) HEAD
hoge.txt
ab
piyo.txt
A
"hoge.txtを更新(S8)"
HEAD~
hoge.txt
a
piyo.txt
A
"piyo.txtを追加(S5)"
HEAD~2
hoge.txt
a
"hoge.txtを追加(S4)"

何らかの作業が終わったら以下の手順で元の状態に戻すことが出来ます。

元の状態に復帰する:

本来の HEAD の名前(ブランチ名)を確認する: git log --all --oneline
本来の HEAD (普通は main か master) に戻る: git checkout -f main (または master)

※ -f はワーキングツリーとインデックスの更新内容を全部捨てて強制的にチェックアウトするオプション

ちゃんと元に戻れたか確認: git log --all --oneline
stash の中を確認: git stash list
ワーキングツリーとインデックスの内容を stash から復元: git stash pop --index

※ --index はインデックスも復元するという意味のオプションです

復元されたか確認

さて状態 17 の状態から上の作業を行うと次の状態18になります。
当然これは元の状態16と同じ状態です。


状態 18 ( = 状態16 )


ワーキングツリー
hoge.txt
a


インデックス
hoge.txt
ab


ローカルリポジトリ「gitlocal」
HEAD
hoge.txt
ab
"piyo.txtを削除(S16)"
HEAD~
hoge.txt
ab
piyo.txt
AB
"piyo.txtを更新(S9)"
HEAD~2
hoge.txt
ab
piyo.txt
A
"hoge.txtを更新(S8)"
HEAD~3
hoge.txt
a
piyo.txt
A
"piyo.txtを追加(S5)"
HEAD~4
hoge.txt
a
"hoge.txtを追加(S4)"