Git
GitHub

git reset 解説

git reset コマンドは、初心者が一番訳が分からないところでしょうか。
このコマンドで色んなことが出来るので、どういう場合にどう使えばいいのか混乱してしまいます。

でも実は、非常にシンプルな動作をしているのです。

git の仕組み

git resetを理解する為に、まずgitの仕組みを抑えておきます。

image.png

developブランチをチェックアウトした状態で、Bのコミット直後を表しています。

項目 説明
develop checkout中のブランチ
A, B コミットデータ
INDEX git add で登録される領域。この内容がコミットとして登録されます。
ワーキングツリー 編集対象のローカルのファイルやディレクトリ

developからワーキングツリーまで縦に並んでいるのは、これらが一致しているということを表しています。

参考:ブランチの真実
ブランチは日本語で「枝」になりますが、gitのブランチはコミットを1つしか持ちません。

ブランチは、どのコミットから始まったかという情報を持っておらず、
あくまでも1コミットに付けられた「別名」に過ぎないのです。

ワーキングツリーを編集

developブランチをcheckoutして、ファイルを編集した状態です。

image.png

ワーキングツリーのみ先に進んでいます。

git add で登録

ワーキングツリーの内容を git add で全て登録した状態です。

image.png

INDEXも進みました。

git commit

INDEXに登録されている内容をコミットした状態です。

image.png

INDEXは、コミットした後も同じ内容で保持されます。

git reset の動き

git reset コマンドは、checkout中のブランチを指定コミットに紐づけ直すという動作をします。

直前のコミットを取り消したい場合

Cをコミットした状態から以下コマンドを実行します。
$ git reset HEAD^

HEADは、checkout中のブランチに紐づいており、つまりはコミットの「別名」にもなります。
^ は、その1つ前のコミットを表すので、HEAD^はBコミットを表します。

コマンド実行後
image.png

HEADとHEADが紐づくブランチ(develop)がBコミットに移動します。
INDEXにもBコミットの内容が反映されます。
ワーキングツリーは変化しません。

これによって、Cのコミット直前に戻ることになります。

ブランチのコミットを全て取り消したい場合

例えば、masterブランチからdevelopブランチを作成してコミット作業を進めていたけど、それらを全て取り消したい、という場合。

$ git reset --hard master
とします。

image.png

master = Aコミットの場合です。

これも同様に、developブランチがmasterブランチと同じコミットに紐づけられる動作です。
INDEXもAコミットの内容が反映されます。

そして、--hard オプションにより、ワーキングツリーにも反映されます。

git add を取り消す場合

git add で登録したこの状態から、
image.png

$ git reset
とすると。

image.png

となります。

これは、
$ git reset

こう書いたのと同じです。
$ git reset HEAD

Bコミットに紐づいている状態から、同じBコミットに紐づけ直すだけなのですが、
その際にINDEXがBコミットの内容で再生成されることで、結果として、git addで登録していた内容がキャンセルされる、
ということになります。