リセット、チェックアウト、元に戻す
git reset
、git checkout
、および git revert
コマンドは、Git ツールボックスで最も便利なツールです。これらはすべて、リポジトリ内の何らかの変更を元に戻します。また、git reset と git checkout を使用すると、コミットまたは個々のファイルを操作できます。
これらはよく似ているため、特定の開発シナリオでどのコマンドを使用すべきかが非常に混同しやすいといえます。この記事では、git reset
、git checkout
、および git revert
の最も一般的な設定を比較します。これにより、皆さんが自信を持ってこれらのコマンドを自在に使用し、リポジトリを移動できるようになることを願っています。
Git リポジトリの 3 つの状態管理メカニズムである作業ディレクトリ、ステージ済みスナップショット、およびコミット履歴に対する影響の観点から各コマンドについて考えると理解に役立ちます。これらのコンポーネントは「Git の 3 つの領域」と呼ばれることもあります。3 つの領域については、git reset
ページで詳しく説明しています。これらのメカニズムを念頭に置いてこの記事を読んでください。
チェックアウトとは、HEAD
ref ポインターを指定されたコミットに移動する操作です。この操作を説明するために、以下のサンプルをご覧ください。

この例は、main
ブランチの連続するコミットを表しています。現在、HEAD
ref と main
ブランチ ref はコミット d を指しています。今度は git checkout b
を実行してみましょう

これは、「コミット履歴」領域への更新です。git checkout
コマンドは、コミットまたはファイル レベルのスコープで使用できます。ファイル レベルのチェックアウトでは、ファイルの内容が特定のコミットの内容に変更されます。
Revert とは、指定されたコミットの逆の操作を行い新しいコミットを作成する操作です。git revert
はコミット レベルのスコープでのみ実行でき、ファイル レベルの機能はありません。
リセットとは、指定したコミットを取り上げ、"3 つの領域" をリセットして、指定したコミットのリポジトリの状態に合わせる操作です。リセットは、3 つの領域に対応する 3 つの異なるモードで起動できます。
チェックアウトとリセットは、通常、ローカルまたはプライベートの「取り消し」を行うために使用されます。リモートの共有リポジトリにプッシュする際に競合を引き起こす可能性があるリポジトリの履歴を変更します。元に戻す操作は、新しい履歴を作成してリモートで共有し、リモートのチーム メンバーが依存している履歴を上書きしないため、「パブリックな取り消し」を行うための安全な操作と見なされています。
Git Reset、Revert、Checkout のリファレンス
以下の表は、これらのすべてのコマンドに関する最も一般的な使用例をまとめたものです。Git の経験を積む間に少なくともこれらの一部は必然的に使用することになるので、このリファレンスを手近に置くようにしてください。
コマンド | スコープ | 一般的な使用例 |
---|---|---|
Git のリセット | コミットレベル | プライベートブランチでコミットを破棄したり、コミットされていない変更を破棄したりします。 |
Git のリセット | ファイルレベル | ファイルのステージ取り消し |
Git checkout | コミットレベル | ブランチの切り替えまたは古いスナップショットの検査 |
Git checkout | ファイルレベル | 作業ディレクトリ内の変更の破棄 |
Git revert | コミットレベル | パブリックブランチ内のコミットの取り消し |
Git revert | ファイルレベル | (N/A) |
コミット レベルの操作
スコープは、git reset
と git checkout
に渡すパラメーターによって決まります。ファイル パスをパラメーターとして含めない場合、コミット全体に作用します。このセクションでは、それについて説明します。git revert
にはファイル レベルの機能はありません。
特定のコミットをリセットする
コミット レベルでは、リセットはブランチの先端を別のコミットに移動する方法です。これは、現在のブランチからコミットを削除するために使用できます。たとえば、次のコマンドは Hotfix
ブランチを 2 つのコミット分後方に移動します。
git checkout hotfix git reset HEAD~2
Hotfix
の最後にあった 2 つのコミットは、中ぶらりんの状態 (孤立したコミット) になりました。つまり、これらは Git が次回ガーベッジ コレクションを実行するときに削除されます。言い換えると、これらのコミットを破棄すると宣言していることになります。これは、次のように視覚化できます。

この git reset
の使用法は、他の誰とも共有していない変更を元に戻す簡単な方法です。フィーチャーで作業を開始して、「しまった、何をやっているんだ。最初からやり直しだ」と思ったときに、頼りになるコマンドです。
現在のブランチを移動することに加えて、次のフラグのいずれかを git reset
に渡してステージ済みスナップショットおよび作業ディレクトリ (またはそのいずれか) を変更することもできます。
--soft
– ステージ済みスナップショットおよび作業ディレクトリは両方ともまったく変更されません。—mixed
— ステージ済みスナップショットは、指定したコミットに一致するように更新されますが、作業ディレクトリには影響しません。これが既定のオプションです。--hard
– ステージ済みスナップショットおよび作業ディレクトリは両方とも指定されたコミットに一致するように更新されます。
これらのモードが git reset
演算のスコープを定義していると考えると理解しやすくなります。詳細については、git reset
ページを参照してください。
古いコミットをチェックアウトする
git checkout
コマンドは、リポジトリの状態をプロジェクト履歴の特定の時点に更新するために使用されます。ブランチ名を指定して渡すと、ブランチ間を切り替えられます。
git checkout hotfix
内部的には、上記のコマンドは HEAD
を別のブランチに移動し、それに合わせて作業ディレクトリを更新するだけです。これはローカルの変更を上書きする可能性があるので、チェックアウト操作中に失われる作業ディレクトリ内の変更を強制的にコミットするか、スタッシュするよう求められます。git reset
と違って、git checkout
はブランチを移動させません。

ブランチの代わりにコミット参照を渡すことで、任意のコミットをチェックアウトすることもできます。これは、ブランチをチェックアウトするのとまったく同じです。HEAD
参照を指定されたコミットに移動します。たとえば、次のコマンドは現在のコミットの祖父母をチェックアウトします。
git checkout HEAD~2
これは、古いバージョンのプロジェクトをすばやく調べるのに便利です。ただし、現在の HEAD
への分岐参照がないため、分離した HEAD
状態になります。これは、別のブランチに切り替えた後にコミットに戻る方法がないため、新しいコミットの追加を開始すると危険です。このため、分離した HEAD
にコミットを追加する前に、必ず新しいブランチを作成する必要があります。
Revert でパブリック コミットを元に戻す
Revert を行うと、新しいコミットが作成されてコミットが取り消されます。これは、コミット履歴が書き換わらないため、変更を元に戻す安全な方法です。たとえば、次のコマンドは、最後から 2 番目のコミットに含まれる変更を特定し、それらの変更を元に戻す新しいコミットを作成し、新しいコミットを既存のプロジェクトに追加します。
git checkout hotfix git revert HEAD~2
これは、次のように視覚化できます。
これを既存のコミット履歴を変更する git reset
と対比してください。このため、git revert
はパブリック ブランチに対する変更を元に戻すために使用し、git reset
はプライベート ブランチに対する変更を元に戻すことだけに使用を制限すべきです。
git revert
はコミットされた変更を元に戻すためのツールで、git reset HEAD
はコミットされていない変更を元に戻すためのツールと考えることもできます。
git checkout
と同様に、git revert
も作業ディレクトリ内のファイルを上書きする可能性があります。このため、ユーザーは、操作中に失われる変更をコミットまたはスタッシュするように求められます。
ファイルレベルのオペレーション
git reset
および git checkout
コマンドも、オプションのファイル パスをパラメーターとして受け入れます。これにより、これらのコマンドの挙動が劇的に変わります。操作がスナップショット全体に及ぶのではなく、1 つのファイルに限定されます。
特定のファイルを Git Reset する
ファイル パスを指定して呼び出されると、git reset
はステージ済みスナップショットを更新して、指定したコミットのバージョンと一致させます。たとえば、次のコマンドは、最後から 2 番目のコミットの foo.py
のバージョンをフェッチし、次のコミットのためにステージングします。
git reset HEAD~2 foo.py
git reset
のコミットレベル バージョンと同様に、これは任意のコミットよりも HEAD
で使用されるほうが一般的です。git reset HEAD foo.py
を実行すると foo.py
のステージングが解除されます。このファイルに含まれる変更は、作業ディレクトリにそのまま残ります。
ステージ済みスナップショットは常に更新され、作業ディレクトリは決して更新されないため、--soft
、--mixed
、および、--hard
フラグはファイル レベル バージョンの git reset
には影響しません。
ファイルを Git Checkout する
ファイルのチェックアウトは、ファイル パスを指定して git reset
を使用する場合と似ていますが、ステージング エリアではなく作業ディレクトリが更新される点が異なります。このコマンドのコミット レベル バージョンとは異なり、HEAD
参照は移動しないため、ブランチは切り替わりません。
たとえば、次のコマンドは作業ディレクトリの foo.py
を最後から 2 番目のコミットからのバージョンと一致させます。
git checkout HEAD~2 foo.py
git checkout
のコミット レベルの呼び出しと同様に、これはプロジェクトの古いバージョンを調べるために使用できますが、スコープは指定されたファイルに限定されます。
チェックアウトしたファイルをステージングしてコミットすると、そのファイルの古いバージョンに「戻す」効果があります。これは、ファイルに対する後続の変更内容をすべて削除することになるため注意が必要です。これに対して、git revert
コマンドは指定されたコミットによって生じた変更のみを元に戻します。
git reset
と同様に、これは通常 HEAD
をコミット リファレンスとして使用します。たとえば、git checkout HEAD foo.py
には、foo.py
に対するステージングされていない変更を破棄する効果があります。これは git reset HEAD --hard
と似た動作ですが、指定されたファイルに対してのみ動作します。
概要
これで皆さんは、Git リポジトリで変更を元に戻すために必要となるすべてのツールを獲得したことになります。git reset
、git checkout
、および git revert
コマンドは混同しやすいですが、作業ディレクトリ、ステージ済みスナップショット、およびコミット履歴に対する影響について考えると目前の開発タスクに適したコマンドを識別することが容易になります。