人間はaddやcommitした直後に間違い発見能力が爆上がりするため、しばしばそれを取り消したくなります。いつもコマンドを打つたびにググっている気がするので、いいかげん覚えるためによく使うコマンドをきちんと調べ、理解し、まとめようと思います。
間違いがあったら教えていただけると嬉しいです。
前提知識
- ワークツリー ... git管理下で実際に作業しているディレクトリのこと。
git add
する前はここにあるイメージ。 - インデックス ... リポジトリにコミットする準備をするための場所のこと。
git add
したらここに移るイメージ。 - リポジトリ ... ファイルやディレクトリの状態を記録する場所。
git commit
したらここに移るイメージ。
最低限これらをざっくり理解しておいた方が良いです。qiitaにもまとめている記事がたくさんあると思うので詳しくはググってください。
addを取り消す
$ git reset HEAD
git-reset - Reset current HEAD to the specified state
そもそもHEADとは何なのか。
HEADとは今自分が作業している場所を示すポインタ
を表します。
Usually the HEAD file is a symbolic reference to the branch you’re currently on.
However in some rare cases the HEAD file may contain the SHA-1 value of a git object. This happens when you checkout a tag, commit, or remote branch, which puts your repository in "detached HEAD" state.
10.3 Git Internals - Git References
簡単に意訳すると、大抵の場合HEADとは現在いるブランチの参照である。たまにタグやコミットなんかをチェックアウトして'detached HEAD'となっているときは最新のコミットは指してないけど。
ブランチ... それぞれ枝分かれしたコミット連の最新コミットを指すポインタ
つまりgit reset HEAD
とは、git add
してインデックスに移ったファイルをHEADの状態(=現在の作業ツリーの状態)にリセットする(=戻す、上書きする)こと。
こちらの方の記事を見ながらだと理解が捗ると思います。
commitを取り消す
$ git reset --soft HEAD^
softもあればhardもある。おまけにmixedもある。
- --soft ... HEADの位置だけ戻す。
- --mixed ... HEADの位置とインデックスを戻す。もしくはオプションなしの場合はこれ(=addの取り消しはこれを使っている)。
- --hard ... HEADの位置とインデックスとワーキングツリーを戻す。要は変更を全くなかったことにする。
つまり上のコマンドはHEADの位置をHEAD^に戻す
ということになる。commitするとHEADの位置が最新のcommitに移るので、それを元に戻すということになる。ということはHEAD^
はひとつ前のcommitを指す。状態としてはadd
までした時点に戻ることになります。
ちなみに^(キャレット)と似たように~(チルダ)がHEADにくっつく(HEAD~)こともありますが、それに関してはこちらの方の記事が参考になります。今回commitを取り消すのは、ローカル作業中で親コミットが1つしかない場合を想定しているので、HEAD^
もHEAD~
も同じ意味になります。
おまけ git add する前の変更を取り消す
git add
もしていない変更をワーキングツリーから削除するには
$ git restore ファイル名
以前は$ git checkout -- ファイル名
を使っていましたが、新しくrestore
ができたのでそちらを使う方が操作間違いが起こりにくいと思います。