git reset コマンドは、初心者が一番訳が分からないところでしょうか。
このコマンドで色んなことが出来るので、どういう場合にどう使えばいいのか混乱してしまいます。
でも実は、非常にシンプルな動作をしているのです。
git の仕組み
git resetを理解する為に、まずgitの仕組みを抑えておきます。
developブランチをチェックアウトした状態で、Bのコミット直後を表しています。
項目 | 説明 |
---|---|
develop | checkout中のブランチ |
A, B | コミットデータ |
INDEX | git add で登録される領域。この内容がコミットとして登録されます。 |
ワーキングツリー | 編集対象のローカルのファイルやディレクトリ |
developからワーキングツリーまで縦に並んでいるのは、これらが一致しているということを表しています。
参考:ブランチの真実
ブランチは日本語で「枝」になりますが、gitのブランチはコミットを1つしか持ちません。
ブランチは、どのコミットから始まったかという情報を持っておらず、
あくまでも1コミットに付けられた「別名」に過ぎないのです。
ワーキングツリーを編集
developブランチをcheckoutして、ファイルを編集した状態です。
ワーキングツリーのみ先に進んでいます。
git add で登録
ワーキングツリーの内容を git add で全て登録した状態です。
INDEXも進みました。
git commit
INDEXに登録されている内容をコミットした状態です。
INDEXは、コミットした後も同じ内容で保持されます。
git reset の動き
git reset コマンドは、checkout中のブランチを指定コミットに紐づけ直すという動作をします。
直前のコミットを取り消したい場合
Cをコミットした状態から以下コマンドを実行します。
$ git reset HEAD^
HEADは、checkout中のブランチに紐づいており、つまりはコミットの「別名」にもなります。
^ は、その1つ前のコミットを表すので、HEAD^はBコミットを表します。
HEADとHEADが紐づくブランチ(develop)がBコミットに移動します。
INDEXにもBコミットの内容が反映されます。
ワーキングツリーは変化しません。
これによって、Cのコミット直前に戻ることになります。
ブランチのコミットを全て取り消したい場合
例えば、masterブランチからdevelopブランチを作成してコミット作業を進めていたけど、それらを全て取り消したい、という場合。
$ git reset --hard master
とします。
master = Aコミットの場合です。
これも同様に、developブランチがmasterブランチと同じコミットに紐づけられる動作です。
INDEXもAコミットの内容が反映されます。
そして、--hard オプションにより、ワーキングツリーにも反映されます。
git add を取り消す場合
$ git reset
とすると。
となります。
これは、
$ git reset
こう書いたのと同じです。
$ git reset HEAD
Bコミットに紐づいている状態から、同じBコミットに紐づけ直すだけなのですが、
その際にINDEXがBコミットの内容で再生成されることで、結果として、git addで登録していた内容がキャンセルされる、
ということになります。