733

についての機微を説明する興味深い投稿を見てきましgit resetた。

残念ながら、それについて読めば読むほど、完全には理解できていないように見えます。私は SVN のバックグラウンドを持っており、Git はまったく新しいパラダイムです。私は水銀を簡単に手に入れましたが、Git ははるかに技術的です。

git resetに近いと思いますがhg revert、違いがあるようです。

では、正確にはgit reset何をするのでしょうか? 以下に関する詳細な説明を含めてください。

  • オプション--hard--softおよび--merge;
  • andHEADなどで使用する奇妙な表記法。HEAD^HEAD~1
  • 具体的なユースケースとワークフロー。
  • 作業コピー、HEADグローバル ストレス レベルへの影響。
4

7 に答える 7

1070

一般に、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 を失いましたCgit 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)は、のようなハッシュ名を使用する必要なく、単にコミットを指定するための省略形です3ebe3f6git-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

キャレットとチルダ

于 2010-03-27T16:48:14.477 に答える
83

あなたが持っていることを覚えておいてくださいgit

  • 作業中のコミットを示すHEADポインタ
  • システム上のファイルの状態を表す作業ツリー
  • 後で一緒にコミットできるように変更を「ステージング」するステージング領域( indexとも呼ばれる)

以下に関する詳細な説明を含めてください。

--hard--softおよび--merge;

危険度の高い順に:

  • --soft移動しますHEADが、ステージング領域または作業ツリーには触れません。
  • --mixedHEADステージング領域を移動および更新しますが、作業ツリーは移動および更新しません。
  • --mergeを移動HEADし、ステージング エリアをリセットし、作業ツリー内のすべての変更を新しい作業ツリーに移動しようとします。
  • --hardステージング エリアと作業ツリーを新しいに移動HEAD してHEAD調整し、すべてを破棄します。

具体的なユースケースとワークフロー。

  • --soft「自分の居場所を失う」ことなく、別のコミットに移動してパッチを適用したい場合に使用します。これが必要になることはほとんどありません。

--

# git reset --soft example
touch foo                            // Add a file, make some changes.
git add foo                          // 
git commit -m "bad commit message"   // Commit... D'oh, that was a mistake!
git reset --soft HEAD^               // Go back one commit and fix things.
git commit -m "good commit"          // There, now it's right.

--

  • --mixed別のコミットでどのように見えるかを確認したいが、既に行った変更を失いたくない場合に使用します (これがデフォルトです)。

  • --merge新しい場所に移動したいが、既に行っている変更を作業ツリーに組み込む場合に使用します。

  • --hardすべてを一掃し、新しいコミットで新たな状態を開始するために使用します。

于 2010-03-27T17:08:11.530 に答える
39

ブログPro Gitの投稿Reset Demystifiedでは、 と について非常に簡単な説明が提供されています。git resetgit checkout

その投稿の冒頭で有益な議論をすべて行った後、著者はルールを次の単純な 3 つのステップに減らします。

それは基本的にそれです。このresetコマンドは、これら 3 つのツリーを特定の順序で上書きし、指示すると停止します。

  1. HEAD が指すブランチを移動します (停止する場合--soft)
  2. 次に、インデックスをそのように表示します (次の場合を除き、ここで終了します--hard) 。
  3. 次に、ワーキングディレクトリをそのようにします

--mergeとオプションもあり--keepますが、今のところはもっと単純にしたいと思います - それは別の記事にします.

于 2011-07-19T14:37:54.473 に答える
6

TL;DR

git resetステージングを最後のコミットにリセットします。--hard作業ディレクトリ内のファイルを最後のコミットにリセットするためにも使用します。

ロングバージョン

しかし、それは明らかに単純化されているため、多くのかなり冗長な回答があります。git reset変更を元に戻すという文脈で読み進めることは、私にとってより理にかなっています。たとえば、これを参照してください:

git revert が変更を元に戻すための「安全な」方法である場合、git reset は危険な方法と考えることができます。git reset を使用して元に戻す場合 (およびコミットが ref または reflog によって参照されなくなった場合)、元のコピーを取得する方法はありません。これは永続的な元に戻すことです。このツールは、作業内容を失う可能性がある数少ない Git コマンドの 1 つであるため、使用する際には注意が必要です。

https://www.atlassian.com/git/tutorials/undoing-changes/git-resetから

この

コミットレベルでは、リセットはブランチの先端を別のコミットに移動する方法です。これは、現在のブランチからコミットを削除するために使用できます。

https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operationsから

于 2015-07-13T17:37:03.463 に答える