Table of Contents
この記事を読んだ、またはGitのオブジェクトモデルを理解していることを前提に、Gitの git revert
と git reset
というコマンドについて説明する。
この二つはしばしばコミットを取り消すコマンドとして同じ文脈で説明されることが多いのでこのエントリでも一緒に説明するが、実際は全く異なるコマンドだし、そもそもどちらもコミットを取り消すコマンドではない。
git revert
git revert
は、指定したコミットが持ち込んだ変更を打ち消すコミットを追加する。
リバースパッチを適用すると言ってもよい。
コミットを追加しかしないので、このコマンドによって既存のコミットが消えたり変わったりすることはない。
図にすると以下の感じ。単純。
git reset
git reset
には二つの機能がある。
インデックスを再設定する(i.e. resetする)機能と、HEAD
を付け替える(i.e. resetする)機能だ。
インデックスの再設定
インデックスの再設定をするコマンドはgit reset <ワーキングディレクトリ内のファイルのパス(複数可)>
。
これを実行すると、指定したファイルについて、HEAD
が指すコミットが指すツリー内のブロブを指すようインデックスを更新する。
何を言っているのかわからないので図にする。
(この図では便宜的にHEAD
、つまり参照をオブジェクト格納領域内に書いているが、実際には別の場所にあることに注意。)
図を見ると、git add Readme.md
とgit reset Readme.md
がだいたい逆のことをしていることがわかる。
要するに、git add <パス>
は指定したファイルをステージし、git reset <パス>
は指定したファイルをアンステージする。
HEADの付け替え
HEAD
の付け替えをするコマンドはgit reset <コミット>
。
これを実行すると、HEAD
が指しているコミットを指すようORIG_HEAD
を作成または更新し、指定したコミットを指すようHEAD
を更新する。
オプションによってはさらにインデックスやワーキングディレクトリを指定したコミットが指すツリーと同期するよう更新する。
このオプションには--soft
、--mixed
(デフォルト)、--hard
の三種類があり、それぞれのオプションを付けた時の更新対象を次の表に示す。
オプション | HEAD | インデックス | ワーキングディレクトリ |
---|---|---|---|
--soft | ○ | ||
--mixed | ○ | ○ | |
--hard | ○ | ○ | ○ |
この三者の違いについては面倒だしだいたい分かるはずなので図にしないが、git reset <コミット>
したときのHEAD
動きについて次に図示する。
スライド中でgit reset HEAD^
した時点で、コミットDは実質的に削除されたに近い状態になる。
ORIG_HEAD
という一時的なシンボリック参照で指されているだけで、どの参照からもたどり着けなくなるからだ。
コミットDはいずれgit gc
によって実際に削除されるはずだし、git push
してもコミットD、それが指すツリー、そのツリーの下にしかないブロブはリモートリポジトリに送られない。
よって、git reset <コミット>
は普通コミットを削除したいときに使われる。
使われはするが、このコマンド自体がコミットを削除するわけではなくて、あくまでHEAD
を付け替えるコマンドであることを覚えていた方がいざというときに助かる。
因みに上のスライドでやった操作は、git commit --amend
がやることとほぼ同じ。