平易な英語で、「git reset」は何をしますか?


674

に関する微妙な点説明する興味深い投稿を見てきましたgit reset

残念ながら、それについて読むほど、完全に理解していないように見えます。私はSVNの出身ですが、Gitはまったく新しいパラダイムです。私は水銀を簡単に手に入れましたが、Gitははるかに技術的です。

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

それで、正確には何をしgit resetますか?以下についての詳細な説明を含めてください:

  • オプション--hard--softおよび--merge;
  • and HEADなどの奇妙な表記。HEAD^HEAD~1
  • 具体的な使用例とワークフロー;
  • 作業コピーへの影響、HEADそしてあなたの全体的なストレスレベル。

17
A Visual Gitリファレンスは、一般的なgitコマンドを使用したときに何が起こるかをよく理解していると思います。

回答:


992

一般的に、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ブランチはに残されましたCDこの時点で新しいコミットを行うと、これが得られますが、これはおそらく望んでいるものではありません。

- 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を元の状態に戻しますが、HEADAと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、第三世代の祖先の第二の親HEADHEAD^^2最初の親の第二の親HEADであっても、あるいはHEAD^^^と等価です、HEAD~3

キャレットとチルド


「そこに移動するにはgit resetを使用します。」なぜgit checkoutを使用しないのですか?
e-satis 2010年

5
@ e-satis:git checkoutはHEADを移動しますが、ブランチをそのままにしておきます。これは、ブランチを移動する場合に使用します。
Cascabel

したがって、私がよく理解している場合、Bをリセットすると次のようになります。-A-B-C-B(マスター)、チェックアウトBは-A-B(マスター)になりますか?
e-satis

32
ドキュメントを読むのに永遠にかかり、ドキュメントが非常に密集していて、彼らがそれがどのように機能するかをすでに知っているように機能していると言うことを確認するのに永遠にかかりますが、ドキュメントは優れています。ドキュメントが私にとって良いように聞こえません...
Kirby

4
stackoverflow.com/questions/3528245/whats-the-difference-between-git-reset-mixed-soft-and-hard:非常にシンプルで理解しやすい説明は、このSOの答えで与えられる
ニティンBansalは

80

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

  • HEADポインタあなたが取り組んでいるコミット何を伝え、
  • 作業ツリーお使いのシステム上のファイルの状態を表し、
  • ステージングエリア(とも呼ばれる指数、彼らは後に一緒にコミットすることができるように変更し、「ステージ」)、

以下についての詳細な説明を含めてください:

--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すべてを一掃し、新しいコミットで新しいスレートを開始するために使用します。


2
これはの使用目的ではありませんreset --merge。3者間マージは実行しません。ドキュメントで説明されているように、実際には競合するマージをリセットするためだけのものです。あなたはあなたが話していることcheckout --mergeをするのに使いたくなるでしょう。ブランチも移動したい場合は、チェックアウト/リセットを続けてドラッグするのが唯一の方法だと思います。
Cascabel

@Jefromi»はい、私はそれをうまく表現していませんでした。「新しいスポット」とは、「マージの競合がない、新鮮な場所」を意味します。
John Feminella、

1
ああ、分かった。私はここで重要なことは、あなたが本当に何をやっている知っている限り、あなたはおそらくこれまでに使用したくないということだと思いますreset --merge(デフォルト)以外の任意のターゲットでHEAD競合のマージを中止以外の場合には、それを捨てるために起こっているので、他の方法で保存できる情報。
Cascabel

2
私はこの答えが最も単純で最も役立つと
感じました

これらのコマンドに関する情報を追加してください:git resetおよびgit reset -- .
Flimm 2013

35

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

その投稿の冒頭で役立つ議論がすべて終わった後、著者はルールを次の簡単な3つのステップに減らします。

それは基本的にそれです。resetコマンドは、あなたがそれを教えてくれたときに停止し、特定の順序でこれら3本の木を上書きします。

  1. HEADが指すブランチを移動します(if ifを停止--soft
  2. 次に、インデックスをそのように見せます(ここで停止しない限り--hard
  3. 次に、ワーキングディレクトリをそのように見せます

--merge--keepオプションもありますが、私は今のところ物事をより単純にしたいと思います-それは別の記事のためになります。


25

gitに何かをコミットするときは、まず変更をステージング(インデックスに追加)する必要があります。つまり、gitがコミットの一部と見なす前に、このコミットに含めたいすべてのファイルをgit追加する必要があります。まずgitリポジトリの画像を見てみましょう: ここに画像の説明を入力してください

それで、今は簡単です。作業ディレクトリで作業し、ファイル、ディレクトリなどを作成する必要があります。これらの変更は追跡されていない変更です。それらを追跡するには、git addコマンドを使用してgitインデックスに追加する必要があります。それらがgitインデックスに追加されると。gitリポジトリにプッシュしたい場合は、これらの変更をコミットできます。

しかし、突然、コミット中に、インデックスに追加した1つの追加ファイルがあることを知りました。gitリポジトリにプッシュする必要はありません。これは、そのファイルをインデックスに含めたくないという意味です。今の質問は、私たちが使用しているので、gitのインデックスからそのファイルを削除する方法ですgitのアドオンをインデックスにそれらを置くために、使用する論理だろうgitのRMを?違う!git rmは単にファイルを削除し、削除をインデックスに追加します。だから今何をすべきか:

使用する:-

git reset

インデックスをクリアし、作業ディレクトリはそのままにします。(単にすべてのステージングを解除します)。

それと一緒に多くのオプションで使用できます。git resetで使用する主なオプションは、--hard、-soft、および--mixedの 3つです。これらは、リセット時にHEADポインターに加えて、何をリセットするかに影響します。

最初に、-- hardはすべてをリセットします。現在のディレクトリは、そのブランチをずっとたどっていた場合とまったく同じです。作業ディレクトリとインデックスがそのコミットに変更されます。これは私が最も頻繁に使用するバージョンです。git reset --hardsvn revertのようなものです。

次に、完全に反対の-softは作業ツリーもインデックスもリセットしません。ヘッドポインターを移動するだけです。これにより、現在の状態は、切り替え先のコミットとは異なる変更がディレクトリに残され、コミットのために「ステージング」されます。ローカルでコミットを行ったが、コミットをgitサーバーにプッシュしていない場合は、前のコミットにリセットして、適切なコミットメッセージで再コミットできます。

最後に、-- mixedはインデックスをリセットしますが、作業ツリーはリセットしません。したがって、変更はすべて残っていますが、「ステージングされていない」ため、git add'edまたはgit commit -aする必要があります。git commit -aで意図した以上にコミットした場合、これを使用することがあります。gitreset --mixedを使用してコミットをバックアウトし、コミットしたいものを追加して、それらをコミットするだけです。

git revertとgit resetの違い:-


簡単に言うと、git reset「コミットされていない間違いを修正するコマンドであり、git revert「コミットされた間違いを修正するコマンドです。

これは、何らかの変更でエラーを発生させてコミットし、それをgit repoにプッシュした場合、git revertが解決策であることを意味します。また、プッシュ/コミットする前に同じエラーを特定した場合は、git resetを使用して問題を修正できます。

それがあなたの混乱を取り除くのに役立つことを願っています。


2
これは、OPからの質問に答える、わかりやすい英語の答えです。
Episodex 2017

1
私はあなたの答えでそれを逃したかもしれませんが。git reset HEADデフォルトは何ですか?--hard--softまたは--mixed?素晴らしい答えです。
giannis christofakis

1
正解ですが、git reset --hardデータが失われる原因となることを明確にします。そして、間違っている可能性のあるポイントがあります(100%確実ではありませんが...まだ学習中です!):--mixed「git commit -aで意図した以上にコミットした場合、これを使用することもあります」とあなたは言う。もしかして:「私たちが意図した以上にステージングした場合git stage .」あなたが本当にそれをコミットしたなら、私はそれは遅すぎると思います(最後に言うように、git resetは「コミットされていない間違いを修正する」コマンドです)
FabioはReinstate Monica

6

TL; DR

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

長いバージョン

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

git revertが変更を元に戻す「安全な」方法である場合、git resetを危険な方法と考えることができます。git resetを使用して元に戻すと(コミットは参照または参照ログによって参照されなくなります)、元のコピーを取得する方法はありません。これは永続的な取り消しです。このツールは作業を失う可能性がある唯一の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から


2

これは、この複雑な機能を理解するための最初のステップとして意図された簡単な説明です。

次の各コマンドの実行後、プロジェクトの状態を視覚化したい視覚学習者に役立ちます。


ターミナルを色付きで使用する場合(git config --global color.ui auto):

git reset --soft A BとCのものは緑色で表示されます(ステージングされ、コミットの準備ができています)

git reset --mixed A(またはgit reset A)そして、BとCのものは赤で表示されます(ステージングされておらず、ステージングの準備ができて(緑)、コミットされます)

git reset --hard A そして、BとCの変更はどこにも表示されなくなります(それらが存在しなかったかのようになります)


または、「Tower」や「SourceTree」などのGUIプログラムを使用するユーザー向け

git reset --soft A そして、「ステージングされたファイル」領域にBとCのものが表示され、コミットの準備ができています。

git reset --mixed A(またはgit reset A)「ステージングされていないファイル」領域にBおよびCのものが表示され、ステージングされてコミットされる準備ができています

git reset --hard A そして、BとCの変更はどこにも表示されなくなります(それらが存在しなかったかのようになります)


1

チェックアウトは、特定のコミットを指します。

リセットは特定のコミットでブランチを指します。(ブランチはコミットへのポインタです。)

ちなみに、あなたの頭がブランチによっても指されているコミットを指していない場合、あなたは分離した頭を持っています。 (間違っていることが判明しました。コメントを参照してください...)


1
つまらないことでありませんが、(はい、実際にそれつまらないですが、完了のために追加しましょう)3番目の文は技術的に誤りです。HEADがブランチBを指していて、ブランチBがコミットabc123を指すとしましょう。ここでcommit abc123をチェックアウトすると、HEADとブランチBの両方がabc123のコミットを指し、HEADが切り離されます。この時点でコミットしても、ブランチBの位置更新されません。あなたは「あなたの頭が枝を指さないなら、あなたは分離した頭を持っている」と言ったかもしれない
RomainValeri

@RomainValeriその状況でコミットは何をしますか?
Ian Warburton、2018年

1
コミットすると、どのブランチからも参照されていないコミットが作成され、ブランチBは、その後複数回コミットした後でも、同じコミットabc123をポイントし続けます。これは、HEADがこの「ワイルド」な一連のコミットの最後のコミットを指さなくなると、これらのコミットがガベージコレクションの候補になることを意味します。
RomainValeri
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.