web-dev-qa-db-ja.com

平易な英語で、 "git reset"は何をするのですか?

おもしろい投稿git resetの微妙な点について説明しました。

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

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

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

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

一般に、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に一致しますが、マスターブランチは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のすべてを他のブランチの状態にリセットし、git reset -- .は現在のディレクトリをHEADの状態にリセットし、簡単なgit resetはすべてをHEADの状態。

メインの作業ツリーとインデックスのオプション

リセット中に作業ツリーとインデックスに何が起こるかを制御する4つの主なオプションがあります。

インデックスはgitの「ステージングエリア」であることに注意してください。コミットの準備中にgit addと言うと、そこが物事の行き先です。

  • --hardは、すべてをリセットしたコミットに一致させます。これはおそらく最も理解しやすいでしょう。ローカルの変更はすべて上書きされます。主な用途の1つは、作業を吹き飛ばすことですが、コミットを切り替えることではありません:git reset --hardgit reset --hard HEADを意味します。もう1つは、ブランチをある場所から別の場所に移動し、インデックス/作業ツリーの同期を維持することです。 これは、作業ツリーを変更するため、実際に作業を失う可能性があります。作業の前にローカルの作業を破棄することを非常に確信してください。 reset --hardを実行します。

  • --mixedがデフォルトです。つまり、git resetgit reset --mixedを意味します。インデックスはリセットされますが、作業ツリーはリセットされません。これは、すべてのファイルが無傷であることを意味しますが、元のコミットとリセットしたコミットの違いは、gitステータスでローカルの変更(または追跡されていないファイル)として表示されます。いくつかの悪いコミットをしたことに気付いたときにこれを使用しますが、それを修正して再コミットできるように、行ったすべての作業を保持したい場合に使用します。コミットするには、ファイルをインデックスに再度追加する必要があります(git add ...)。

  • --softは、インデックスまたは作業ツリーに触れません。すべてのファイルは--mixedと同様にそのままですが、すべての変更はgitステータスでchanges to be committedとして表示されます(つまり、コミットの準備でチェックインされます)。いくつかの悪いコミットをしたことに気付いたときにこれを使用しますが、作業はすべて良いです-あなたがする必要があるのは、それを別の方法で再コミットすることです。インデックスは変更されていないため、必要に応じてすぐにコミットできます。結果のコミットには、リセット前と同じ内容がすべて含まれます。

  • --mergeは最近追加されたもので、失敗したマージの中止を支援することを目的としています。これは、git mergeが実際には、変更によってマージの影響を受けないファイルにある限り、ダーティな作業ツリー(ローカルに変更されたもの)とのマージを試行できるためです。 git reset --mergeは、インデックスをリセットし(--mixed-すべての変更がローカルの変更として表示される)、マージの影響を受けるファイルをリセットしますが、他のファイルはそのままにします。これにより、うまくいけば、すべてが不良マージ前の状態に復元されます。ブランチを実際に移動するのではなく、マージをリセットするだけでよいため、通常はgit reset --mergegit reset --merge HEADを意味する)として使用します。 (HEADは、マージに失敗したため、まだ更新されていません)

    具体的には、ファイルAとBを変更し、ファイルCとDを変更したブランチでマージしようとするとします。マージは何らかの理由で失敗し、中止することにしました。 git reset --mergeを使用します。 CとDをHEADの状態に戻しますが、AとBへの変更はマージの一部ではないため、変更はそのままにします。

もっと知りたい?

man git resetはこれに非常に適していると思います。おそらくgitが実際に沈み込むためにはgitの動作を少し理解する必要があります。特に、時間をかけて注意深く読んでいると、さまざまなオプションやケースのインデックスと作業ツリーにあるファイルの状態を詳細に示した表が非常に役立ちます。 (しかし、はい、それらは非常に高密度です-それらは非常に簡潔な形式で上記の情報の非常に多くを伝えています。)

奇妙な表記

あなたが言及する「奇妙な表記法」(HEAD^およびHEAD~1)は、3ebe3f6のようなハッシュ名を使用することなく、コミットを指定するための単なる略記です。これは、git-rev-parseのmanページの "specifying revisions"セクション に完全に文書化されており、多くの例と関連構文があります。キャレットとチルダは、実際には 異なるもの を意味します。

  • HEAD~HEAD~1の略で、コミットの最初の親を意味します。 HEAD~2は、コミットの最初の親の最初の親を意味します。 HEAD~nを「HEADの前にn回コミット」または「HEADの第n世代の祖先」と考えてください。
  • HEAD^(またはHEAD^1)は、コミットの最初の親も意味します。 HEAD^2は、コミットのsecond親を意味します。通常のマージコミットには2つの親があります。最初の親はマージ先コミットであり、2番目の親はマージされたコミットです。一般に、マージは実際に任意の数の親を持つことができます(タコマージ)。
  • ^および~演算子は、HEADHEAD~3^2、2番目の第3世代の祖先の2番目の親であるHEAD^^2のように、一緒に連結できます。 HEAD、またはHEAD^^^と同等のHEAD~3の最初の親の親。

caret and tilde

954
Cascabel

gitには以下のものがあります。

  • HEADポインタ 、あなたが取り組んでいるコミットを教えてくれます
  • システムのファイルの状態を表す 作業ツリー
  • ステージング領域 index とも呼ばれる)、 "ステージング"が変更され、後で一緒にコミットできるようになります。

詳細な説明を含めてください。

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

危険度の高いものから順に:

  • --softHEADを動かしますが、ステージング領域や作業ツリーには触れません。
  • --mixedHEADを移動してステージング領域を更新しますが、作業ツリーは更新しません。
  • --mergeHEADを移動し、ステージング領域をリセットし、そして作業ツリーのすべての変更を新しい作業ツリーに移動しようとします。
  • --hardHEADを移動してステージング領域と作業ツリーを新しい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を使用してすべてを消去し、新しいコミットで新しいスレートを開始します。

77
John Feminella

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

この記事の冒頭にある有益な議論をすべて終えて、作者はルールを次の簡単な3つのステップにまとめました。

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

  1. HEADが指すブランチを移動します(--softの場合は停止します)。
  2. それでは、インデックスをそのように見せてください(--hard以外はここで止めてください)
  3. それで、作業ディレクトリをそのように見せてください

--merge--keepオプションもありますが、今のところもっと単純にしておきたいと思います - それは別の記事のためになるでしょう。

35

Gitするために何かをコミットするとき、あなたは最初にあなたの変更をステージング(インデックスに追加)しなければなりません。これは、gitがそれらをコミットの一部と見なす前に、このコミットに含めたいすべてのファイルをgit addしなければならないことを意味します。まず、Gitリポジトリのイメージを見てみましょう。 enter image description here

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

しかし、突然、インデックスに追加した1つの追加ファイルがgitリポジトリにプッシュするのに必要ではないことをコミットしている間に知るようになりました。そのファイルをインデックスに入れたくないということです。さて、問題はgitインデックスからそのファイルを削除する方法です。インデックスにそれらを入れるためにgit addを使ったのでgit rmを使うのは論理的でしょうか?違う! git rmは単にファイルを削除し、その削除をインデックスに追加します。だから今何をすべきか:

つかいます:-

gITリセット

インデックスを消去し、作業ディレクトリをそのまま残します。 (単にすべてを展開する)。

それはそれと一緒にオプションの数で使用することができます。 git resetで使用する3つの主なオプションがあります:--hard、 - soft、 - mixed。これらは、リセットしたときのHEADポインタに加えて、リセットされる内容に影響します。

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

次に、完全に反対の—softは、作業ツリーもインデックスもリセットしません。 HEADポインタを移動するだけです。これはあなたの現在の状態をあなたがあなたのディレクトリの中に配置しようとしているコミットとは異なる、そしてコミットのために「段階的に」変更されたままで残します。ローカルでコミットしてもgitサーバーにコミットをプッシュしていない場合は、前のコミットにリセットして、正しいコミットメッセージで再コミットできます。

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

git revertとgit resetの違い : -


簡単に言うと、git reset"未修正の間違い"へのコマンド、git revert"未確定の間違い"へのコマンドです。

ある変更に何らかのエラーを犯し、それをgit repoにコミットしてプッシュしたのであれば、git revertが解決策です。また、プッシュ/コミットする前に同じエラーが見つかった場合は、git resetを使用して問題を解決できます。

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

24
love

TL、DR

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

長期版

しかし、それは明らかに単純化されているので、かなり冗長な答えです。変更を元に戻すという文脈でgit resetを読むことは私にとってより意味がありました。例えば。これを見てください。

Git revertが変更を元に戻すための「安全な」方法であれば、git resetを危険な方法と考えることができます。 git resetを使って元に戻す(そしてコミットがrefやreflogから参照されなくなった)場合、元のコピーを取り出す方法はありません - それは永久的な元に戻すことです。このツールは、作業を失う可能性がある唯一のGitコマンドなので、このツールを使用するときは注意が必要です。

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

この

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

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

6
Snowcrash

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

次の各コマンドの実行後に自分のプロジェクトの状態がどのようになるかを視覚化したい視覚学習者には便利です。


カラーをオンにしてTerminalを使う人のために(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のものがコミットの準備が整った「staged files」領域に表示されます。

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

git reset --hard Aなら、あなたはもはやどこにもBとCの変化を見ないでしょう(まるでそれらが存在しなかったかのようになるでしょう)

2
timhc22

チェックアウトはヘッドを特定のコミットに向けます。

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

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

1
Ian Warburton