git resetをちゃんと理解する
はじめに
過去を振り返ってみて、git の理解が一段階深まったなと感じたのは git の HEAD の概念を理解したときだった。そしてその HEAD と密接に関連しているのが git reset コマンドだと思う。
なので git reset コマンドをちゃんと理解できれば HEAD の概念の理解も進み、git の理解も深まるのではないかと考えた。ということで、この記事では git reset についてちゃんと理解するための説明を試みたい。
git reset コマンドは何をするのか
git reset は HEAD を移動する コマンドである。
HEAD とは何か
では HEAD とは何か?
HEAD とは、今いるブランチの最新のコミットを指し示すポインタ である。
例えばリポジトリ A を git 管理しているとして、リポジトリ A で git log コマンドを実行したときに次のような状態だったとしよう。
$ git log --oneline
193c77e Third commit ★ HEAD
69d2f53 Second commit
1010114 First commit
この場合、最新コミットの 193c77e Third commit が HEAD だ。
git reset [mode] [commit]
git reset コマンドにはいくつかのコマンド体系があるが、最もよく使うのは git reset [mode] [commit] の形式での実行だろうと思う。
上述の通り git reset コマンドは HEAD を移動するコマンドであった。よってこのコマンドは [commit]の位置まで HEAD を移動する ということを意味する。
そして[mode]は、HEAD を移動するときに「ステージングエリア」と「作業ディレクトリ」を更新するかどうか を指定するオプションとなる。
—
以下、具体例で見てみよう。次の状態のリポジトリがあるとする。
A、B、C の3つのコミットがあり、何も変更を加えていない状態。HEAD は最新のコミットである C を指している。

git status コマンドを実行すると次の結果が返ってくる。何も差分が発生していないクリーンな状態だ。
$ git status
On branch master
nothing to commit, working tree clean
git reset —soft HEAD^
mode を --soft、commit を HEAD^ にして reset をすると、HEAD は1つ前のコミットに移動させるが、ステージングエリアと作業ディレクトリはそのままの状態にする。
※ HEAD^ は最新コミットの1つ前を示す特殊な指定方法(だがよく使う)

git status コマンドの結果は次の通り。git add をした状態と考えても良い。
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file.txt
git reset —mixed HEAD^
mode を --mixed、commit を HEAD^ にして reset をすると、HEAD とステージングエリアを1つ前のコミットに移動させ、作業ディレクトリはそのままの状態にする。
--mixed が mode のデフォルト値である。

git status コマンドの結果は次の通り。git add をする前の状態と考えても良い。
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
git reset —hard HEAD^
mode を --hard、commit を HEAD^ にして reset をすると、HEAD、ステージングエリア、作業ディレクトリの全てを1つ前のコミットに移動させる。

git status コマンドの結果は次の通り。差分の発生していないクリーンな状態だが、前のコミットである C の情報は消え去っている。
$ git status
On branch master
nothing to commit, working tree clean
おまけ:ファイルパスを指定した git reset
git reset コマンドはファイルパスを指定して実行する形式もある。この場合、指定したファイルをある状態に戻すが、HEAD 自体は動かさない という動きになる。
この形式の git reset を使う典型的なパターンは、「間違えて git add してしまったので取り消したい」というケースだろう。以下例。
—
間違えて git add してしまった!

git reset [path] で 指定したファイルを、HEAD の状態に戻す。 すなわち、作業ディレクトリだけ変更が反映された「git add する前の状態」に戻ることになる。
