一般的に、git reset
の機能は、現在のブランチを取得して、別の場所を指すようにリセットし、場合によってはインデックスと作業ツリーを一緒にすることです。より具体的には、マスターブランチ(現在チェックアウトされている)が次のような場合:
- A - B - C (HEAD, master)
そして、マスターがCではなくBを指すようにしたいことに気づきgit reset B
ました。
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
余談:これはチェックアウトとは異なります。を実行するとgit checkout B
、次のようになります。
- A - B (HEAD) - C (master)
あなたは切り離されたHEAD状態になりました。HEAD
、作業ツリー、インデックスはすべて一致B
しますが、masterブランチはに残されましたC
。D
この時点で新しいコミットを行うと、これが得られますが、これはおそらく望んでいるものではありません。
- A - B - C (master)
\
D (HEAD)
リセットはコミットを行わず、ブランチ(コミットへのポインター)を更新して別のコミットを指すことを覚えておいてください。残りは、インデックスと作業ツリーに何が起きるかの詳細です。
ユースケース
git reset
次のセクションのさまざまなオプションの説明の中で、主な使用例の多くを取り上げます。それは実際に多種多様なものに使用できます。共通のスレッドは、ブランチ、インデックス、および/または作業ツリーをリセットして、特定のコミットを指す/一致させることです。
注意すること
--hard
あなたは本当に仕事を失う原因となる可能性があります。作業ツリーを変更します。
git reset [options] commit
コミットが(ある程度)失われる可能性があります。上記のおもちゃの例では、コミットを失いましたC
。それはまだリポジトリ内にあり、git reflog show HEAD
またはを見れば見つけることができますgit reflog show master
が、実際にはどのブランチからもアクセスできなくなりました。
Gitはそのようなコミットを30日後に完全に削除しますが、それまではブランチを再度ポイントすることでCを回復できます(git checkout C; git branch <new branch name>
)。
議論
manページを言い換えると、最も一般的な使用法はの形式git reset [<commit>] [paths...]
で、指定されたパスを指定されたコミットからその状態にリセットします。パスが指定されていない場合はツリー全体がリセットされ、コミットが指定されていない場合はHEAD(現在のコミット)と見なされます。これはgitコマンド(たとえば、正確なセマンティクスは異なりますが、checkout、diff、logなど)で共通のパターンであるため、それほど驚くべきことではありません。
たとえばgit reset other-branch path/to/foo
、path / to / fooのすべてをother-branchの状態にgit reset -- .
リセットし、現在のディレクトリをHEADの状態にgit reset
リセットし、単純にすべてをHEADの状態にリセットします。
主な作業ツリーとインデックスオプション
リセット中に作業ツリーとインデックスに何が起こるかを制御する4つの主なオプションがあります。
覚えておいてください、インデックスはgitの「ステージング領域」です- git add
コミットする準備をしていると言うとき、それは物事が行くところです。
--hard
すべてをリセットしたコミットと一致させます。これはおそらく理解するのが最も簡単です。ローカルの変更はすべて破棄されます。一つの主な用途はあなたの仕事を離れて吹いたがコミットをスイッチングしていない:git reset --hard
手段git reset --hard HEAD
、すなわち枝を変更しませんが、すべてのローカルの変更を取り除きます。もう1つは、ブランチをある場所から別の場所に移動するだけで、インデックス/作業ツリーの同期を維持します。これは、作業ツリーを変更するため、実際に作業を失う原因となります。実行する前に、ローカルの作業を破棄することを非常に確実にしてくださいreset --hard
。
--mixed
デフォルトは、つまりをgit reset
意味しgit reset --mixed
ます。インデックスはリセットされますが、作業ツリーはリセットされません。つまり、すべてのファイルは変更されていませんが、元のコミットとリセットしたコミットの違いは、gitステータスのローカル変更(または追跡されていないファイル)として表示されます。不正なコミットを行ったことがわかったが、修正して再コミットできるように、実行したすべての作業を保持したい場合に、これを使用します。コミットするには、ファイルを再度インデックスに追加する必要があります(git add ...
)。
--soft
インデックスや作業ツリーには触れません。すべてのファイルはと同様にそのままですが--mixed
、すべての変更changes to be committed
はgitステータスと同様に表示されます(つまり、コミットの準備としてチェックインされます)。これは、いくつかの悪いコミットをしたことがわかったが、作業はすべて良好である場合に使用します。必要なのは、別の方法で再コミットすることだけです。インデックスは変更されていないため、必要に応じてすぐにコミットできます。結果のコミットには、リセットする前と同じ内容がすべて含まれます。
--merge
は最近追加され、失敗したマージの中止を支援することを目的としています。git merge
これらの変更がマージの影響を受けないファイルにある限り、実際にはダーティな作業ツリー(ローカルで変更されたもの)とのマージを試行できるため、これは必要です。git reset --merge
インデックスをリセットし(--mixed
すべての変更はローカルの変更として表示されます)、マージの影響を受けるファイルをリセットしますが、他のファイルはそのままにします。これはうまくいけば、悪いマージの前の状態にすべてを復元します。マージをリセットするだけで、実際にはブランチを移動しないため、通常はgit reset --merge
(つまりgit reset --merge HEAD
)として使用します。(HEAD
マージが失敗したため、まだ更新されていません)
より具体的には、ファイルAとBを変更し、ファイルCとDを変更したブランチでマージしようとしたとします。マージは何らかの理由で失敗し、中止することにしました。あなたが使用しますgit reset --merge
。CとDを元の状態に戻しますが、HEAD
AとBへの変更はそのままにしておきます。これらは、試みられたマージの一部ではなかったためです。
もっと知りたい?
私man git reset
は本当にこれにはかなり良いと思います-おそらくあなたはそれらが本当に沈み込むためにgitがどのように動作するかの感覚を少し必要とするでしょう。特に、時間をかけてじっくり読むと、さまざまなオプションやケースすべてについて、インデックス内のファイルの状態とワークツリーの詳細を示すこれらの表が非常に役立ちます。(しかし、そうです、それらは非常に密集しています-上記の情報の非常に多くを非常に簡潔な形で伝えています。)
奇妙な表記
あなたが言及する「奇妙な表記」(HEAD^
およびHEAD~1
)は、コミットの指定の省略形であり、などのハッシュ名を使用する必要はありません3ebe3f6
。git-rev-parseのmanページの「Specifying revisions」セクションに、多くの例と関連する構文が記載されています。キャレットとチルドは実際には異なる意味を持っています:
HEAD~
はの略でHEAD~1
、コミットの最初の親を意味します。HEAD~2
コミットの最初の親の最初の親を意味します。HEAD~n
「nはHEADの前にコミット」または「HEADのn世代の祖先」と考えてください。
HEAD^
(またはHEAD^1
)は、コミットの最初の親も意味します。HEAD^2
コミットの2番目の親を意味します。通常のマージコミットには2つの親があります。最初の親はマージ先のコミットで、2番目の親はマージされたコミットです。一般的に、マージは実際には任意の数の親を持つことができます(タコマージ)。
^
そして~
オペレータは同様に、つなぎ合わせすることができHEAD~3^2
、第三世代の祖先の第二の親HEAD
、HEAD^^2
最初の親の第二の親HEAD
であっても、あるいはHEAD^^^
と等価です、HEAD~3
。