git reset についてもまとめてみる

前回 git diff を図に書いてみたところ、自分の中で意外と整理できたので、これまたなんとなく使っていた git reset についてもまとめてみた。


とりあえず結論を先にまとめよう。

git reset とは?
HEAD の位置を変更するコマンド。
オプションによってインデックス、ワーキングツリーの内容も変更できる。


git reset のオプションは?
--soft、--mixed(オプションなしと同等)、--hard オプションがあり、影響度の小さい順に以下のようになる。

  • --soft
    • HEAD の位置のみを変更する。インデックス、ワーキングツリーには影響なし。
  • --mixed (またはオプションなし)
    • HEAD の位置とインデックスを変更する。ワーキングツリーには影響なし。
  • --hard
    • HEADの位置、インデックス、ワーキングツリーをすべて変更する。

さて、git reset の説明に入る前に一旦 HEAD、インデックス、ワーキングツリーの関係について整理しておく。

初期状態

前回のコミットが完了してからまだ何も修正していない状態。
インデックスの内容もワーキングツリーの内容も HEAD に一致している。


ファイル修正

ファイルを修正したため、ワーキングツリーの内容はHEADとは異なるようになる。
ただ、まだ git add していないため、インデックスの内容は HEAD と同じまま。


git add

git add するとインデックスに現在のワーキングツリーの状態が反映される。


さらにファイル修正

git add した後にもファイルの修正をしても別に問題ない。
この場合、下の図のように HEAD、インデックス、ワーキングツリーの内容はすべて異なるようになる。




この状態から git reset を行ったらどうなるかを見ていこう。

git reset --soft HEAD

HEAD の位置を HEAD に変更し、インデックス、ワーキングツリーはそのままにする。
つまり何も変わらない。


git reset --soft HEAD^

HEAD の位置が HEAD^ に移動するだけ。
前の HEAD にアクセスできなくなる!?と思うかもしれないけど、ORIG_HEAD や git-reflog でいくらでも元に戻せるので心配無用。


git reset HEAD

HEAD、インデックスを HEAD に変更する。ワーキングツリーはそのまま。
これを実行すると変更前のインデックスにはアクセスできなくなるので要注意。*1
git add を取り消す方法としてよく使われる。


git reset HEAD^

今度はワーキングツリーの変更を残しつつ、HEAD、インデックスを HEAD^ に変更する。
これも変更前のインデックスの内容は失われる。*2


git reset --hard HEAD

HEAD、インデックス、ワーキングツリーすべてを HEAD に変更する。
変更前のHEAD、インデックスは復元する方法があるが、ワーキングツリーの内容は完全に失われるので要注意。


git reset --hard HEAD^

HEAD、インデックス、ワーキングツリーすべてを HEAD^ に変更する。




--merge、--keep というオプションもあるみたいだけど、この 3 種類さえ使えれば 99% 事足りる気がする。
後は、自分が HEAD +何の内容を変更したいかさえ意識すれば git reset は使いこなせると思う。

*1:git-gc する前なら git-fsck でなんとか辿りつけるらしい。詳しくは知らない

*2:git-fsck で頑張れば(ry