一般に、git resetの機能は、現在のブランチを取得して別の場所を指すようにリセットし、場合によってはインデックスと作業ツリーを一緒に移動することです。より具体的には、マスター ブランチ (現在チェックアウトされている) が次のような場合:
- A - B - C (HEAD, master)
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しますが、マスター ブランチは に取り残されましたC。この時点で新しいコミットを行うDと、これが得られますが、これはおそらくあなたが望んでいるものではありません:
- A - B - C (master)
\
D (HEAD)
リセットはコミットを行わないことを覚えておいてください。別のコミットを指すようにブランチ (コミットへのポインター) を更新するだけです。残りは、インデックスと作業ツリーに何が起こるかの詳細です。
ユースケース
git reset次のセクションでは、さまざまなオプションの説明の中で、主な使用例の多くを取り上げます。それは本当にさまざまなことに使用できます。共通のスレッドは、ブランチ、インデックス、および/または作業ツリーをリセットして、特定のコミットを指す/一致させることです。
注意事項
--hard本当に仕事を失う可能性があります。作業ツリーを変更します。
git reset [options] commitコミットを失う可能性があります。上記のおもちゃの例では、 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リセットしたコミットにすべてを一致させます。これが一番分かりやすいです、たぶん。ローカルの変更はすべて上書きされます。主な用途の 1 つは、コミットを切り替えずに作業を吹き飛ばすことです。つまり、ブランチを変更せずにすべてのローカル変更を取り除くことをgit reset --hard意味します。git reset --hard HEADもう 1 つは、単純にブランチをある場所から別の場所に移動し、インデックス/作業ツリーの同期を維持することです。これは、作業ツリーを変更するため、実際に作業を失う可能性があるものです。を実行する前に、ローカルの作業を破棄したいことを十分に確認してくださいreset --hard。
--mixedがデフォルトです。つまり、git resetを意味しgit reset --mixedます。インデックスはリセットされますが、作業ツリーはリセットされません。これは、すべてのファイルが無傷であることを意味しますが、元のコミットとリセットしたコミットとの違いは、ローカルの変更 (または追跡されていないファイル) として git ステータスで表示されます。これは、いくつかの不適切なコミットを行ったことに気付いたが、修正して再コミットできるように、行ったすべての作業を保持したい場合に使用します。コミットするには、インデックスにファイルを再度追加する必要があります ( git add ...)。
--softインデックスや作業ツリーには触れません。すべてのファイルはそのままですが--mixed、すべての変更はchanges to be committedgit ステータス (つまり、コミットの準備のためにチェックインされている) と同じように表示されます。いくつかの悪いコミットを行ったことに気付いたが、作業はすべて順調であることに気付いた場合にこれを使用してください。必要なのは、別の方法で再コミットすることだけです。インデックスはそのままなので、必要に応じてすぐにコミットできます。結果のコミットには、リセット前と同じ内容がすべて含まれます。
--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 ページの「リビジョンの指定」セクションに、多くの例と関連する構文とともに完全に文書化されています。キャレットとチルダは実際には異なる意味を持ちます:
HEAD~の略でHEAD~1、コミットの最初の親を意味します。HEAD~2コミットの最初の親の最初の親を意味します。HEAD~n「HEADの前のnコミット」または「HEADのn世代の祖先」と考えてください。
HEAD^(またはHEAD^1) は、コミットの最初の親も意味します。HEAD^2コミットの2 番目の親を意味します。通常のマージ コミットには 2 つの親があることに注意してください。最初の親はマージ先のコミットで、2 番目の親はマージされたコミットです。一般に、マージは実際には任意の数の親を持つことができます (octopus マージ)。
^and演算子は、、 の第 3 世代の先祖の2 番目の親、 の最初の親の 2 番目の親、またはと同等ののよう~に、一緒に並べることができます。HEAD~3^2HEADHEAD^^2HEADHEAD^^^HEAD~3
