Resetting, checking out & reverting
The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.
これらはよく似ているため、特定の開発シナリオでどのコマンドを使用すべきかが非常に混同しやすいといえます。この記事では、git reset
、git checkout
、および git revert
の最も一般的な設定を比較します。これにより、皆さんが自信を持ってこれらのコマンドを自在に使用し、リポジトリを移動できるようになることを願っています。
It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.
チェックアウトとは、HEAD
ref ポインターを指定されたコミットに移動する操作です。この操作を説明するために、以下のサンプルをご覧ください。
関連資料
Git リポジトリ全体を移動する方法
ソリューションを見る
Bitbucket Cloud での Git の使用方法についてのチュートリアルです。
この例は、main
ブランチの連続するコミットを表しています。現在、HEAD
ref と main
ブランチ ref はコミット d を指しています。今度は git checkout b
を実行してみましょう
これは、「コミット履歴」領域への更新です。git checkout
コマンドは、コミットまたはファイル レベルのスコープで使用できます。ファイル レベルのチェックアウトでは、ファイルの内容が特定のコミットの内容に変更されます。
Revert とは、指定されたコミットの逆の操作を行い新しいコミットを作成する操作です。git revert
はコミット レベルのスコープでのみ実行でき、ファイル レベルの機能はありません。
リセットとは、指定したコミットを取り上げ、"3 つの領域" をリセットして、指定したコミットのリポジトリの状態に合わせる操作です。リセットは、3 つの領域に対応する 3 つの異なるモードで起動できます。
チェックアウトとリセットは、通常、ローカルまたはプライベートの「取り消し」を行うために使用されます。リモートの共有リポジトリにプッシュする際に競合を引き起こす可能性があるリポジトリの履歴を変更します。元に戻す操作は、新しい履歴を作成してリモートで共有し、リモートのチーム メンバーが依存している履歴を上書きしないため、「パブリックな取り消し」を行うための安全な操作と見なされています。
Git reset vs revert vs checkout reference
以下の表は、これらのすべてのコマンドに関する最も一般的な使用例をまとめたものです。Git の経験を積む間に少なくともこれらの一部は必然的に使用することになるので、このリファレンスを手近に置くようにしてください。
コマンド | スコープ | 一般的な使用例 |
---|---|---|
| スコープ コミットレベル | 一般的な使用例 Discard commits in a private branch or throw away uncommitted changes |
| スコープ ファイルレベル | 一般的な使用例 ファイルのステージ取り消し |
| スコープ コミットレベル | 一般的な使用例 ブランチの切り替えまたは古いスナップショットの検査 |
| スコープ ファイルレベル | 一般的な使用例 作業ディレクトリ内の変更の破棄 |
| スコープ コミットレベル | 一般的な使用例 パブリックブランチ内のコミットの取り消し |
| スコープ ファイルレベル | 一般的な使用例 (N/A) |
Commit level operations
スコープは、git reset
と git checkout
に渡すパラメーターによって決まります。ファイル パスをパラメーターとして含めない場合、コミット全体に作用します。このセクションでは、それについて説明します。git revert
にはファイル レベルの機能はありません。
Reset a specific commit
コミット レベルでは、リセットはブランチの先端を別のコミットに移動する方法です。これは、現在のブランチからコミットを削除するために使用できます。たとえば、次のコマンドは Hotfix
ブランチを 2 つのコミット分後方に移動します。
git checkout hotfix git reset HEAD~2
Hotfix
の最後にあった 2 つのコミットは、中ぶらりんの状態 (孤立したコミット) になりました。つまり、これらは Git が次回ガーベッジ コレクションを実行するときに削除されます。言い換えると、これらのコミットを破棄すると宣言していることになります。これは、次のように視覚化できます。
この git reset
の使用法は、他の誰とも共有していない変更を元に戻す簡単な方法です。フィーチャーで作業を開始して、「しまった、何をやっているんだ。最初からやり直しだ」と思ったときに、頼りになるコマンドです。
現在のブランチを移動することに加えて、次のフラグのいずれかを git reset
に渡してステージ済みスナップショットおよび作業ディレクトリ (またはそのいずれか) を変更することもできます。
--soft
– ステージ済みスナップショットおよび作業ディレクトリは両方ともまったく変更されません。—mixed
— ステージ済みスナップショットは、指定したコミットに一致するように更新されますが、作業ディレクトリには影響しません。これが既定のオプションです。--hard
– ステージ済みスナップショットおよび作業ディレクトリは両方とも指定されたコミットに一致するように更新されます。
It’s easier to think of these modes as defining the scope of a git reset
operation. For further detailed information visit the git reset page.
古いコミットをチェックアウトする
git checkout
コマンドは、リポジトリの状態をプロジェクト履歴の特定の時点に更新するために使用されます。ブランチ名を指定して渡すと、ブランチ間を切り替えられます。
git checkout hotfix
内部的には、上記のコマンドは HEAD
を別のブランチに移動し、それに合わせて作業ディレクトリを更新するだけです。これはローカルの変更を上書きする可能性があるので、チェックアウト操作中に失われる作業ディレクトリ内の変更を強制的にコミットするか、スタッシュするよう求められます。git reset
と違って、git checkout
はブランチを移動させません。
ブランチの代わりにコミット参照を渡すことで、任意のコミットをチェックアウトすることもできます。これは、ブランチをチェックアウトするのとまったく同じです。HEAD
参照を指定されたコミットに移動します。たとえば、次のコマンドは現在のコミットの祖父母をチェックアウトします。
git checkout HEAD~2
これは、古いバージョンのプロジェクトをすばやく調べるのに便利です。ただし、現在の HEAD
への分岐参照がないため、分離した HEAD
状態になります。これは、別のブランチに切り替えた後にコミットに戻る方法がないため、新しいコミットの追加を開始すると危険です。このため、分離した HEAD
にコミットを追加する前に、必ず新しいブランチを作成する必要があります。
Undo public commits with 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
も作業ディレクトリ内のファイルを上書きする可能性があります。このため、ユーザーは、操作中に失われる変更をコミットまたはスタッシュするように求められます。
File-level operations
git reset
および git checkout
コマンドも、オプションのファイル パスをパラメーターとして受け入れます。これにより、これらのコマンドの挙動が劇的に変わります。操作がスナップショット全体に及ぶのではなく、1 つのファイルに限定されます。
Git reset a specific file
ファイル パスを指定して呼び出されると、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 file
ファイルのチェックアウトは、ファイル パスを指定して 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
と似た動作ですが、指定されたファイルに対してのみ動作します。
要約
You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.
この記事を共有する
次のトピック
おすすめコンテンツ
次のリソースをブックマークして、DevOps チームのタイプに関する詳細や、アトラシアンの DevOps についての継続的な更新をご覧ください。