2020-04-12

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を指している。

2020-04-12-01.jpg
2020-04-12-01.jpg

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つ前を示す特殊な指定方法(だがよく使う)

2020-04-12-02.jpg
2020-04-12-02.jpg

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のデフォルト値である。

2020-04-12-03.jpg
2020-04-12-03.jpg

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つ前のコミットに移動させる。

2020-04-12-04.jpg
2020-04-12-04.jpg

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 してしまった!

2020-04-12-05.jpg
2020-04-12-05.jpg

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

2020-04-12-06.jpg
2020-04-12-06.jpg

参考URL