Git reset で HEAD位置を変えないとき

git resetは、HEADを戻すコマンド。だが、インデックスの削除など HEAD を戻す以外の使い方もあり、混乱したのでまとめておく。

$ git reset <オプション> <コミット>

コミットは、コミットのハッシュのほか、HEAD やブランチ名などで指定する。指定しなかった場合は HEAD となる。

git reset のオプション

オプション 動作
--soft HEAD だけ戻す
[--mixed] HEAD とインデックスを戻す
--hard HEAD とインデックスとワークツリーを戻す

(--mixed は省略可)

git reset でコミットを指定しない(=HEADを指定する)とき

HEAD は、通常、最新コミットを指す。

コマンド 動作
git --soft HEAD 何も変わらない
git [--mixed] HEAD インデックスを戻す
git --hard HEAD インデックスとワークツリーを戻す

例1

  • Aというファイルを作って、
  • git add A して、コミット。
  • Bというファイルを作って、
  • git add B して、コミット。
  • Cというファイルを作って、
  • git add C した。

という状況。

git reset

git reset HEAD は、インデックスを HEAD の内容に戻す。

f:id:masuyama13:20200824230846j:plain

add したことをキャンセル(unstage)するのに、git reset HEAD が使われる。

ただ、このコマンドは git restore --staged に変わりつつあることも知っておきたい。(関連記事

git reset --hard

git reset --hard HEAD は、ワークツリーとインデックスを HEAD の内容に戻す。つまり、最新コミット直後のような状態になる。

f:id:masuyama13:20200824230905j:plain

例2

  • Aというファイルを作って、
  • git add A して、コミット。
  • Bというファイルを作って、
  • git add B して、コミット。
  • Cというファイルを作った。

インデックスにはまだ追加していないという状況。

git reset

git reset HEAD は、インデックスを HEAD の内容に戻すので、この例では何も変わらない。

f:id:masuyama13:20200824230922j:plain

git reset --hard

git reset --hard HEAD は、ワークツリーとインデックスを HEAD の内容に戻す。

git status のメッセージによると、ステージしていない変更を破棄するには checkout(または restore)を使う)

f:id:masuyama13:20200824230937j:plain

Untracked files に注意

ここが初心者(自分)にとっては罠だった。

git reset --hard (HEAD) すると、インデックスとワークツリーが最新コミットの状態に戻る。と書いてあったりする。

ただし、Untracked files(まだ一度も git に add されていないファイル)は影響を受けない。つまり、最新コミットの後新たに作ったファイルは消えず、Untracked files として残ったままになる。

Git を使っている人たちには当然すぎることなので言及されていないのだろうが、最初そこがわかっておらず、git reset --hard したのにワークツリーが戻ってない!やっぱり git わからん…となった。

Untracked files は、reset してもブランチを切り替えても影響を受けないということを覚えた。