h3pei.tech
お仕事のご依頼
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

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

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

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

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

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

2020-04-12-06.jpg

参考 URL

h3pei's icon

h3pei

フリーランスのソフトウェアエンジニア。Ruby / Rails アプリケーションの開発が得意領域。設計・実装・運用まで含めてプロダクト開発が好きです。

Questalという目標達成コミュニティサービスを開発しました。仲間と一緒に目標達成に取り組みたい方はぜひご利用ください。

お仕事のご依頼
GitHubnoteX

関連記事