はじめに
git reset --hard [コミットのハッシュ値]
を実行すると、指定したコミット以降のコミット履歴が消去されてしまうので、
過去のコミット時のコードを一時的に見たいときは、コミット履歴に影響を与えないgit switch -d [コミットのハッシュ値]
を使ったほうが良さそうということに気づきました。
(git reset --hard [コミットのハッシュ値]
を実行してコミット履歴を消去しても、一応復元できますが。)
筆者自身、詳しいことを知らずにgit reset --hard [コミットのハッシュ値]
を使って焦ったことがあるので、両者の違いをまとめておきます。
サンプルの解説
以下のようなテキストファイルがあるとします。
first
second
third
fourth
ブランチについては、feature-1
という作業ブランチにいるとします。
* feature-1
main
コミットの履歴については、main
ブランチで空のテキストファイルを作成したのち、最初のコミットをしています。
そして、feature-1
ブランチを作成してそこに移動しています。
その後、add first
というコミットでテキストファイルにfirst
を書いて、
add second
というコミットでテキストファイルにsecond
を書いて、...
という流れになっています。
commit 444444444444444 (HEAD -> feature-1)
Author: your name
Date: Mon Jan 4 00:00:00 2024
add fourth
commit 333333333333333
Author: your name
Date: Mon Jan 3 00:00:00 2024
add third
commit 222222222222222
Author: your name
Date: Mon Jan 2 00:00:00 2024
add second
commit 111111111111111
Author: your name
Date: Mon Jan 1 00:00:00 2024
add first
commit 000000000000000 (main)
Author: your name
Date: Sun Dec 31 00:00:00 2023
first commit
(※実際には000000000000000
などの部分はもっと長いハッシュ値になっています。以降も同様。)
git reset --hard をするとどうなるのか
はじめに、git reset --hard [コミットのハッシュ値]
を実行するとどうなるのか見ていきましょう。
git reset --hart 222222222222
を実行して、add second
コミットの状態にリセットを行うと、
HEAD is now at 2222222222 add second
と表示され、ファイルの中身は
first
second
になります。、add second
コミット時の状態になっていますね。
続いて、git branch
でブランチを確認してみると、
* feature-1
main
特に変化はないようです。
続いてgit log
で履歴を見てみます。
commit 222222222222222
Author: your name
Date: Mon Jan 2 00:00:00 2024
add second
commit 111111111111111
Author: your name
Date: Mon Jan 1 00:00:00 2024
add first
commit 000000000000000 (main)
Author: your name
Date: Sun Dec 31 00:00:00 2023
first commit
見てのとおり、add second
以降のコミットが消えてしまっています。
過去のコミットの状態にリセットしたいときはこの方法で良いと思います。
しかし、一時的に過去のコミットに戻ってコードを見たいだけの場合、git reset --hard [コミットのハッシュ値]
を実行すると、最新のコミットに戻れなくなってしまいます。
戻す方法について
「git reset --hard [コミットのハッシュ値]
を実行すると、最新のコミットに戻れなくなってしまう」と書きましたが、一応戻す方法はあるようです。
まず、git reflog
を実行します。
2222222 (HEAD -> feature-1) HEAD@{0}: reset: moving to 222222222222222
4444444 HEAD@{1}: commit: add fourth
3333333 HEAD@{2}: commit: add third
2222222 (HEAD -> feature-1) HEAD@{3}: commit: add second
1111111 HEAD@{4}: commit: add first
0000000 (main) HEAD@{5}: checkout: moving from main to feature-1
0000000 (main) HEAD@{6}: commit (initial): first commit
すると、このように操作履歴を見ることができます。
今回の場合、一行目の
2222222 (HEAD -> feature-1) HEAD@{0}: reset: moving to 222222222222222
が、「git reset --hard [コミットのハッシュ値]
でリセットを実行した操作に該当します。
リセットする前の状態、つまり二行目の
4444444 HEAD@{1}: commit: add fourth
の状態に戻りたいので、
git reset --hard 4444444
またはgit reset --hard HEAD@{1}
を実行して、リセットする前の状態にリセットします。すると、
first
second
third
fourth
このように、ファイルの中身が最後のadd fourth
コミットの状態に戻りました。
git log
でログを見てみても、
commit 444444444444444 (HEAD -> feature-1)
Author: your name
Date: Mon Jan 4 00:00:00 2024
add fourth
commit 333333333333333
Author: your name
Date: Mon Jan 3 00:00:00 2024
add third
commit 222222222222222
Author: your name
Date: Mon Jan 2 00:00:00 2024
add second
commit 111111111111111
Author: your name
Date: Mon Jan 1 00:00:00 2024
add first
commit 000000000000000 (main)
Author: your name
Date: Sun Dec 31 00:00:00 2023
first commit
元に戻せているのが確認できます。
git switch -d を使うとどうなるのか
先ほどまでは、git reset --hard [コミットのハッシュ値]
を使った場合を見てきました。
次にgit switch -d [コミットのハッシュ値]
を使った場合を見ていきましょう。
add fourth
までコミットされた状態であることを確認して、
first
second
third
fourth
commit 444444444444444 (HEAD -> feature-1)
Author: your name
Date: Mon Jan 4 00:00:00 2024
add fourth
commit 333333333333333
Author: your name
Date: Mon Jan 3 00:00:00 2024
add third
commit 222222222222222
Author: your name
Date: Mon Jan 2 00:00:00 2024
add second
commit 111111111111111
Author: your name
Date: Mon Jan 1 00:00:00 2024
add first
commit 000000000000000 (main)
Author: your name
Date: Sun Dec 31 00:00:00 2023
first commit
git switch -d 222222222222222
を実行してみると、
HEAD is now at 2222222 add second
と表示され、テキストファイルを見てみると、
first
second
add second
コミット時のファイルが表示されています。
git branch
でブランチを見てみると、
* (HEAD detached at 2222222)
feature-1
main
現在(HEAD detached at 2222222)
にいることがわかります。
ただしこれは、depatched HEAD
という状態であり、ブランチが作成されているわけではないので注意してください。
(この状態で作業をしても保存されません)
depatched HEAD
については以下の記事がわかりやすいかと思います。
git log
でコミットの履歴を見てみると、
commit 222222222222222
Author: your name
Date: Mon Jan 2 00:00:00 2024
add second
commit 111111111111111
Author: your name
Date: Mon Jan 1 00:00:00 2024
add first
commit 000000000000000 (main)
Author: your name
Date: Sun Dec 31 00:00:00 2023
first commit
指定したコミットとそれ以前のコミットが表示されています。
add third
とadd fourth
コミットが消えているように見えますが、実際は消えておらず、feature-1
ブランチに戻ると、きちんと全て表示されます。
git switch feature-1
でもとのブランチに戻ってみると、
first
second
third
fourth
最後のadd fourth
コミットの状態になっていることがわかります。
git log
で履歴を見てみても、
commit 444444444444444 (HEAD -> feature-1)
Author: your name
Date: Mon Jan 4 00:00:00 2024
add fourth
commit 333333333333333
Author: your name
Date: Mon Jan 3 00:00:00 2024
add third
commit 222222222222222
Author: your name
Date: Mon Jan 2 00:00:00 2024
add second
commit 111111111111111
Author: your name
Date: Mon Jan 1 00:00:00 2024
add first
commit 000000000000000 (main)
Author: your name
Date: Sun Dec 31 00:00:00 2023
first commit
コミットの履歴が全て残っていることが確認できます。
ちなみにこの状態で、git branch
でブランチ一覧を表示させると、
* feature-1
main
先ほどまであった(HEAD detached at 2222222)
が無くなっていることがわかります。
これは、(HEAD detached at 2222222)
がdepatched HEAD
という状態であり、ブランチが実際に作成されているわけではないためです。そのため、他のブランチに移動してしまうと(HEAD detached at 2222222)
は消えてしまいます。
depatched HEADを避けるには
depatched HEAD
状態を避けた状態で過去のコミットに戻りたいときは、ブランチを作ってあげる必要があります。
git switch -c [作成するブランチの名前] [コミットのハッシュ値]
または
git switch -d [コミットのハッシュ値]
を実行してdepatched HEAD
の状態でgit switch -c [作成するブランチの名前]
を実行すると、特定のコミットの状態のブランチを作った上で、そのブランチに移動できます。
試しに、feature-1
ブランチにいる状態で
first
second
third
fourth
git switch -c add-second 222222222222222
を実行すると、
first
second
* add-second
feature-1
main
add second
コミットの状態になっており、さらにadd-second
ブランチが作成されていることがわかります。
switchの代わりにcheckoutも使える
ちなみにcheckout
コマンドを使っても、同じようなことができます。
git checkout 222222222222222
を実行すると、
NOTE: switching to '222222222222222'.
You are in 'detached HEAD' state. 以下略
HEAD is now at 2222222 add second
first
second
* (HEAD detached at 2222222)
feature-1
main
となります。
おわりに
間違い等ございましたら、教えていただけますと幸いです。
参考文献