git reset --mixed、-soft、および--hardの違いは何ですか?


741

コミットを分割して、どのリセットオプションを使用するかわからない。

私はページを平易な英語で見ていましたが、「git reset」は何をしますか?、しかし私はgitインデックスまたはステージング領域が何であるかを本当に理解していないため、説明が役に立たないことに気付きました。

また、その答えのユースケース--mixed--soft私には同じように見えます(修正して再コミットする場合)。誰かがそれをさらに分解できますか?私--mixedはおそらくオプションを選択することを理解していますが、その理由を知りたいのです。最後に、どう--hardですか?

3つのオプションの選択がどのように行われるかのワークフローの例を誰かに教えてもらえますか?


1
他の質問の回答を編集して、もう少し明確にしてみましょう。
Cascabel 2010

@mkarasekの回答はかなり良いですが、この質問を見てみることに興味があるかもしれません。
brandizzi

3
自己への注意:一般的にはsoft: stage everythingmixed: unstage everythinghard: ignore everythingコミットまでに私からリセットしています。
user1164937


David Zych明確な説明がある別の良い記事-davidzych.com/difference-between-git-reset-soft-mixed-and-hard
src3369

回答:


1489

リポジトリ内のファイルを変更すると、変更は最初はステージングされません。コミットするには、を使用してステージングする、つまりインデックスに追加する必要がありますgit add。コミットを行う場合、コミットされる変更は、インデックスに追加されたものです。

git reset少なくとも、現在のブランチ(HEAD)が指している場所を変更します。違い--mixedとは--soft、あなたのインデックスも修正されているかどうかです。したがって、masterこの一連のコミットでブランチにいる場合:

- A - B - C (master)

HEADを指しC、インデックスが一致しCます。

実行するgit reset --soft Bmaster(したがってHEAD)はを指しBますが、インデックスにはからの変更がありCます。git statusステージとして表示されます。したがってgit commit、この時点で実行すると、と同じ変更が加えられた新しいコミットが取得されCます。


では、ここからもう一度始めましょう。

- A - B - C (master)

今やりましょうgit reset --mixed B。(注:--mixedはデフォルトのオプションです)。もう一度、B masterHEADポイントしますが、今回はインデックスもに合わせて変更されBます。git commitこの時点で実行すると、インデックスがと一致するため、何も起こりませんHEAD。作業ディレクトリにはまだ変更がありますが、インデックスにgit statusはないため、ステージングされていないものとして表示されます。それらをコミットするには、git add通常どおりコミットします。


最後に、作業ディレクトリも変更することを除いて、(とを変更する)と--hard同じです。私たちがしている場合は、実行、その後に追加の変更だけでなく、あなたが持っているすべてのコミットされていない変更は、削除されます、そして、あなたの作業コピー中のファイルがコミット一致します。この方法で変更を永久に失う可能性があるため、ハードリセットを行う前に必ず実行して、作業ディレクトリがクリーンであること、またはコミットされていない変更を失ってもよいことを確認してください。--mixedHEAD--hardCgit reset --hard BCBgit status


そして最後に、視覚化: ここに画像の説明を入力してください


45
つまり、-softは最後のコミットを破棄し、-mixは最後のコミットと追加を破棄し、-hardは最後のコミットと追加を破棄し、git checkout HEADと同じコードに加えた変更を破棄します
James Wang

11
@eventualEntropy reflogを使用して、コミットされた変更を回復できます。で削除されたコミットされていない変更はreset --hard永久に失われます。
mkarasek 2014

2
@ロバートどちらも; --mixedインデックスは変更されますが、作業ディレクトリは変更されないため、ローカルでの変更は影響を受けません。
mkarasek 2014

3
端末でgitを色付きで使用する視覚的な人に役立つ場合があります:1.'git reset --soft A 'とBとCのものが緑色(段階的)で表示されます2.'git reset --mixed A'とあなたはBおよびCのものを赤で表示(ステージングなし)3.'git reset --hard A 'すると、BおよびCの変更が​​どこにも表示されなくなります(存在しないかのように
見えます

2
@ user1933930 1と3はのままにします- A - B - C′。C 'にはCと同じ変更が含まれます(タイムスタンプが異なり、メッセージがコミットされる可能性があります)。図2及び図4は、であなたを残す- A - DDはBとCの組み合わせの変更を含む場合、
mkarasek

215

最も簡単な言葉で:

  • --soft:変更をコミットせず、変更はステージングされたままです(index)。
  • --mixed (デフォルト)uncommit + unstage changes、変更は作業ツリーに残ります
  • --harduncommit + unstage +変更を削除し、何も残っていません。

8
答えは技術用語を使用して、最も簡潔でもある完全な答えを提供するため、ベストアンサー
Trevor Boyd Smith

1
ファイルを(プッシュしないで)コミットし、新しく作成された追跡されていないファイルがある場合、git reset --hardは何もしませんか?追跡されていないファイルをステージングした場合にのみ、作業ディレクトリから削除されます。
マイケル

1
@Nikhilこの答えが間違っているところを説明できますか?
Ned Batchelder 2018年

1
@NedBatchelderポイントのいずれも正しくありません。これらのコマンドを使用すると、コミット解除は発生しません。
Nikhil

1
@Nikhilおそらく、あなたが言っていることは、オリジナルのコミットがまだ存在しているということです。しかし、ブランチは変更されたため、コミットはブランチの一部ではなくなりました。私たちはそれに同意しますか?
Ned Batchelder、2018年

69

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

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


ターミナルを色付きで使用する場合(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
これは、せいぜい誤解を招くgit resetだけです。あなたの答えは、git statusの出力の外観のみを変更するかのように解釈されます。
jub0bs 2014年

3
私はあなたの要点を理解していますが、視覚的な学習者として、3つのコマンドを使用した後に私のプロジェクトがどのように「見えた」かを見て、最終的に彼らが何をしていたかを理解するのに役立ちました!
timhc22 2014年

私は、人々が実際に起こっていることを容易にするのを助けるために、それが「ダミーのためのgit」の種類のアイデアのより多くを見た。誤解を
招か

8
いいえ、この回答を変更する必要はありません。便利な「チートシート」を提供します。考えてみてください:ソフト=緑、混合=赤、ハード=何も(意味がなくなった)!覚えやすい!これらの色が実際に何を意味するのかさえ理解していない初心者の場合、Gitについてあまり知識がなく、とにかくハードなレッスンを受けますが、それは@unegmaのせいではありません!ところで、私はこの回答に賛成票を投じて、以前の反対票を打ち消しました。よくやった、@ unegma!
RayLuo、2015

5
これは、他の場所で読んだときの内部の仕組みをよりよく理解するための優れた補足的な要約として役立ちました。ありがとうございました!
2015年

24

他のすべての答えは素晴らしいですが、私はそれが最高の三つのカテゴリーにファイルを破壊することによって、それらを理解するために見つけます:unstagedstagedcommit

  • --hard 理解しやすいはずです、それはすべてを復元します
  • --mixed (デフォルト)
    1. unstagedファイル:変更しない
    2. staged ファイル:移動 unstaged
    3. commit ファイル:移動 unstaged
  • --soft
    1. unstagedファイル:変更しない
    2. stagedファイル:変更しないでください
    3. commit ファイル:移動 staged

要約すれば:

  • --softオプションはすべて(unstagedファイルを除く)をstaging area
  • --mixed オプションはすべてをに移動します unstaged area

22

TortoiseGitユーザー向けの基本的な説明は次のとおりです。

git reset --soft--mixedファイルはそのままにしておきます。

git reset --hard実際にファイル変更して、リセットしたコミットに一致させます。

TortoiseGitでは、インデックスの概念はGUIによって非常に隠されています。ファイルを変更する場合git add、ステージング領域/インデックスに変更を追加するために実行する必要はありません。単純にファイル名を変更し、されていない既存のファイルへの変更を扱う場合git reset --soft--mixed同じです!新しいファイルを追加したり、ファイルの名前を変更した場合にのみ、違いがわかります。この場合、git reset --mixedを実行すると、バージョン管理されていないファイルのリストからファイルを再度追加する必要があります。


この答えは、ソフトと混合の違いについて非常に不明確です。そしてそれを述べることでさえ否定的です。この次の答えは、それについてより明確です。stackoverflow.com/questions/2530060/...
barlop

2
同じ動作をするGithubデスクトップのユーザーとして、この回答は、なぜとについて混乱し続けるのかを明確に--mixed--softます。
Chen Li Yong

20

これらの場合、うまくいけばこれを説明できるビジュアルが好きです。

git reset --[hard/mixed/soft]

ここに画像の説明を入力してください

したがって、それぞれが異なるスコープに影響します

  1. ハード=> WorkingDir +インデックス+ HEAD
  2. 混合=>インデックス+ヘッド
  3. ソフト=>ヘッドのみ(インデックスと作業ディレクトリは変更されません)。

15

後悔の3つのタイプ

既存の回答の多くは、実際の質問に答えていないようです。これらは、コマンドが何を実行するかに関するものであり、ユーザー(ユーザー)が望むもの(ユースケース)についてではありません。しかし、それはOPが尋ねたものです!

コマンドを出したときに後悔していることが正確に何であるかという点で説明をまとうことは、より役立つかもしれませんgit reset。これがあるとしましょう:

A - B - C - D <- HEAD

以下は、後悔の可能性とその対処方法です。

1. B、C、Dは1つのコミットではないことを後悔しています。

git reset --soft A。Aからのすべての変更 1つのコミットであるので、すぐにコミットしてプレスすることができます。

2. B、C、Dは10回のコミットではないことを後悔しています。

git reset --mixed A。コミットはなくなり、インデックスはAに戻りますが、作業領域はDの後と同じように見えます。これで、まったく別のグループで追加とコミットを行うことができます。

3. B、C、Dがこのブランチで発生したことを後悔しています。Aの後に分岐していて、他の分岐で起こっていたらよかったのに。

新しいブランチotherbranchを作成し、次にgit reset --hard A。現在のブランチはAで終わり、そこotherbranchから派生しています。

(もちろん、B、C、およびDがまったく発生しないことを望むので、ハードリセットを使用することもできます。)


5

それらの違いを覚えるように強制する必要はありません。実際にコミットした方法を考えてください。

1.変更を加えます。

2.git add。

3.gc -m「何かをした」

Soft、Mixed、Hardは、3から1に行った操作をあきらめる方法です。

あなたが「gc -m」をしたことが決してないようにソフトな「ふり」。

「git add」を実行したことがないように、「ふりをした」混合。

あなたがファイルの変更を行ったことを決して見ないように「偽装」するのは難しい。


4

これら3つのオプションに入る前に、3つのことを理解する必要があります。

1)歴史/ヘッド

2)ステージ/インデックス

3)作業ディレクトリ

reset --soft:履歴が変更され、HEADが変更され、作業ディレクトリは変更されません。

reset --mixed:履歴が変更され、HEADが変更され、作業ディレクトリがステージングされていないデータで変更されました。

reset --hard:履歴が変更され、HEADが変更され、作業ディレクトリが変更され、データが失われました。

Git --softを使用しても常に安全です。複雑な要件では、他のオプションを使用する必要があります。


3

について誤解されている回答がいくつかありますgit reset --soft。(デタッチされたヘッドの状態から開始して)git reset --softのみ変更される特定の条件がありますがHEAD、通常(および意図された用途)、現在チェックアウトしているブランチ参照が移動します。もちろん、ブランチをチェックアウトしていない場合は、これを行うことはできません(したがって、git reset --soft変更されるのは特定の条件のみですHEAD)。

これがを考える最良の方法であることがわかりましたgit reset。あなただけ動いていないHEADすべてがそれを行い、あなたも移動している)分岐REFを、例えば、master。これは、新しいコミットを作成する(そして移動する)代わりに、以前のコミットに移動することを除いgit commitて、実行(現在のブランチがに沿って移動するHEAD)と同じです。

これが、ブランチreset変更せずに、新しいコミット以外のものに変更するという点です。HEAD これはドキュメントの例で見ることができます:

コミットを元に戻し、トピックブランチにします

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. あなたはいくつかのコミットを行いましたが、それらが「マスター」ブランチになるのは時期尚早であることに気づきました。トピックブランチでそれらを磨き続けたいので、現在のHEADから「topic / wip」ブランチを作成します。
  2. masterブランチを巻き戻して、これらの3つのコミットを削除します。
  3. 「topic / wip」ブランチに切り替えて作業を続けます。

この一連のコマンドの意味は何ですか?ここでブランチを移動したいmasterので、masterチェックアウトした状態で実行しgit resetます。

ここで投票した上位の回答は概ね良好ですが、誤解のあるいくつかの回答を修正するためにこれを追加したいと思いました。

ブランチを変更する

git reset --soft <ref>:現在チェックアウトされているブランチのブランチポインターを、指定された参照でのコミットにリセットします<ref>。作業ディレクトリとインデックス内のファイルは変更されません。この段階からコミットすると、git resetコマンドの前の状態に戻ります。

インデックスも変更する

git reset --mixed <ref>

または同等に

git reset <ref>

何が--softない、指定の基準にコミット試合にインデックスをリセットします。一方でgit reset --soft HEAD(それはブランチをチェックアウトしにブランチをチェックアウトした移動言うので)何もしない、git reset --mixed HEADまたは同等git reset HEAD、それはあなたの最後のコミットの状態にインデックスをリセットするので、一般的で便利なコマンドです。

作業ディレクトリも変更します

git reset --hard <ref>:何をし--mixedていも作業ディレクトリを上書きします。このコマンドは、ブランチ参照が指しているすべての形式の移動git checkout <ref>を除いて(そしてこれがについての重要なポイントですreset)、に似ています。git resetHEAD

「そのようなコマンドはHEADを移動する」に関するメモ:

コマンドがを移動すると言っても意味がありませんHEAD。コミット履歴のどこにいるかを変更するコマンドを実行すると、が移動しHEADます。それは何HEAD 、どこにいてもへのポインタ。HEADあなたであり、そうするたびに移動します。


2
「ブランチ参照の移動」:良い点。stackoverflow.com/a/5203843/6309を更新する必要がありました。
VonC

1

3つのオプションがどのコンテキストで使用されているかについての短い回答:

コードの現在の変更維持しながら、コミット履歴を書き換えるには:

  • soft:一度にすべてをコミットし、新しい説明で新しいコミットを作成できます(gitまたはその他のほとんどのGUIをローテーションする場合は、これを使用します。コミットするファイルにチェックマークを付けて複数にすることができるためです)別のファイルでそのようにコミットします。Sourcetreeでは、すべてのファイルがコミット用にステージングされます。)
  • mixed:コミットする前に、個々のファイルをインデックスに再度追加する必要があります(Sourcetreeでは、変更されたファイルはすべてステージングされません)。

コードの変更を実際に失うには:

  • hard:履歴を書き換えるだけでなく、リセットした時点までのすべての変更を失う

この場合、私は柔らかく、混合しないでください。コミットする必要がある場合、何が元に戻されましたか?元に戻す、または変更を再コミットしますか(元の状態に戻りますか?)
John Little

変更を再コミットします。リバースコミットはありません。
Nickpick 2017年

1

git resetコマンドのさまざまなオプションの基本的な違いは次のとおりです。

  • --soft:選択したコミットにのみHEADをリセットします。基本的にgit checkoutと同じように機能しますが、ヘッドが切り離された状態にはなりません。
  • --mixed(デフォルトオプション):HEADを履歴で選択したコミットにリセットし、インデックスの変更を元に戻します。
  • --hard:両方の履歴で選択したコミットにHEADをリセットし、インデックスの変更を元に戻し、作業ディレクトリの変更を元に戻します。

1

--soft:HEADを別のコミットにリセットするようにGitに指示するため、インデックスと作業ディレクトリはまったく変更されません。元のHEADとコミットの間で変更されたすべてのファイルがステージングされます。

--mixed:ソフトのように、これはHEADを別のコミットにリセットします。また、作業ディレクトリは変更されませんが、一致するようにインデックスをリセットします。すべての変更は作業ディレクトリに残り、変更されたように見えますが、ステージングされません。

--hard:これはすべてをリセットします-HEADを別のコミットにリセットし、それに一致するようにインデックスをリセットし、それに一致するように作業ディレクトリもリセットします。

主な違い--mixedとは--soft、あなたのインデックスも修正されているかどうかです。詳しくはこちらをご覧ください


0

mkarasekの回答は素晴らしく、簡単に言えば...

  • git reset --soft:をHEAD目的のコミットに設定しますが、最後のコミットから変更を段階的に保持します
  • git reset --mixed:それは同じですgit reset --softが、唯一の違いは、最後のコミットからの変更のステージングを解除することです
  • git reset --hardHEAD指定したコミットに設定し、コミットされていない変更を含む最後のコミットからのすべての変更をリセットします。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.