開発ブログ
Git、CSS、HTML、正規表現など、入門者がつまづきそうなポイントを中心に、役立ち情報発信します。。

git reset の基本仕様と、主要なオプションのまとめ

最終更新:2018-04-12 by Joe

Git で発生する「取り消し」の操作において重要なコマンドの一つ「git reset」。今回、git reset の詳細な仕様の理解を焦点をあて、できるだけ分かりやすくまとめてみました。

git reset の機能

git reset は、下記の2つ機能を持つコマンドです。コマンド実行時のパラメータにファイルパスを指定すれば(1)、そうでなくコミットやコミットへの参照を指定すれば(2)の動作です。2つの動作は明確に異なります。

git reset の2種類の機能

  1. インデックスの状態をリセットする
  2. ブランチの先頭(HEAD)を、指定したコミットに強制移動する

コマンドは、下記のような引数のとり方です。

// [1] インデックスの状態をリセットする
git reset <commit> <file>
git reset <file>

// [2] ブランチの先頭を、指定したコミットに強制移動する
git rest <commit>

なお、ファイルパスの指定は「<コミット> <パス>」または「<コミット> -- <パス>」のように、どのコミットにおけるファイルなのかを指定することができます。

git reset の利用ケース

1インデックスの状態をリセットする

「git reset <ファイルパス>」はインデックスの変更内容を取り消すコマンドです。上記(1)にあたるこの機能は主に、インデックスを直前のコミット直後にリセットする目的で利用されます。

例)git add を取り消す「git reset HEAD <ファイルパス>」

Git において、「HEAD」は通常「現在のブランチの先頭コミット」を参照しています。「git reset HEAD」と指定すれば、インデックスの状態が直近のコミットと同じ状態になりますので、これはすなわち「インデックスの変更を取り消し、元に戻す」という動作になります。

git add とそれを取り消す git reset の関係。

実際は「git reset」引数を省略すると、デフォルトでHEADが指定されたことになりますので、「git rest」のみ実行すればOKです。

git rest は「git add の正反対」ではない

上記の図を書くとしばしば誤解されるので、注意が必要なのが、例えば「最後のcommitから2回以上のaddした」という場合、1回目の変更含めて、すべてリセットされてしまいます。ですので、本当の意味での、「git addコマンドの実行1回分の取り消し」はgitでは不可能です。git reset はあくまでリセットであり、1回のadd実行を取り消してくれるわけではないのです。

git では一般的に、コミットしたり、stashしていない変更内容は、一度失われると取り返せません。

2ブランチの先頭を、指定したコミットに強制移動する

「git rest <commit>」として、ファイルパスの指定をしなければ、現在のブランチの先頭である「HEAD」を強制的に指定したコミットに移動させる事ができます。これは、上記の(2)の機能にあたり、インデックスを書き換えるだけの(1)とは明確に異なる機能です。

さらに、デフォルトでは、HEADの移動と同時に、インデックスをリセット先のコミットと一致させます。作業ツリーはそのままです。この作業ツリーとインデックスの更新に関する動作を、オプションを付けることで、切り替えることができます。

それでは、次のセクションで詳しくオプションについて見ていきましょう。

git reset の hard/soft オプションについて

さて、git reset の代表的な3種類のモードを使い分けについてです。

git reset はデフォルトでは、HEADとインデックスを更新し、作業ツリーをそのままにします。一方で、--softモードでは、HEADを移動して、インデックスも作業ツリーもそのままです。さらに、逆に --hard モードでは、作業ツリーもろともリセットを適応します。

これらの違いを、図で比べてみましょう。

git reset での、soft, hard のリセットの範囲の違い。

表でも比較してみます。

モード影響範囲
git reset --softHEAD(現在のブランチの先頭)だけをリセットします。
git reset
git reset --mixed
HEAD(現在のブランチの先頭)とインデックスをリセットします。作業ツリーはそのままです。
git reset --hardHEAD(現在のブランチの先頭)とインデックス、および作業ツリーをリセットします。

下記にオプションを使った具体的な使用例を紹介します。

例1git commit の実行を取り消す「git reset --soft HEAD^」

最新のコミットの内容をちょっとだけ修正したい時に「 git reset --soft HEAD^」とすると、インデックスには最新の変更をのこしたまま、HEAD だけを一つ前に巻き戻します。これによって、直前のgit commit 実行を取り消して、それがまだコミットされていない状態に戻れます。

例えば、もし「デバッグコード削除し忘れ」の修正であれば、あとはコードを削除して git commit を実行するだけでコミットをやり直せる、というわけです。

これは「git commit --amend」でも代用できる振る舞いです。--amend オプションのほうが直感的ですので、あえて soft モードを使う必要はないかもしれません。

例2過去のコミット直後に強制的に戻す「git rest --hard <commit>」

--hard は、例えば、「ローカルブランチをリモートブランチで強制上書きする」などする時に、手元の開発環境を強制的に特定の状態に戻したい時、一撃必殺技的に使うことが多いと思います。

例えば、ローカルの master ブランチが、なぜか origin/master と食い違ってしまって、「とりあえずリモートに合わせたい!」などという状況では、コマンド一撃でその状態に合わせる事ができるのです。

下図は食い違ってしまった master を、origin/master に強制的に合わせるイメージです。

とにかく、インデックス、作業ツリーの状態を無視して(変更があろうがなかろうが吹き飛ばして)origin/masterと同じ状態を作り出します。

非常にパワフルですが、一歩間違えると、作業中の変更を抹消してしまうので、実行までにgit status で、状態を確認してから行いましょう。

参考情報

git reset に関するリンクです。

Git 公式ドキュメントです。

閉じる