日本語 ▾ トピック ▾ 最新バージョン ▾ git-reset は 2.50.0 で最終更新されました

名前

git-reset - 現在のHEADを指定された状態にリセットする

概要

git reset [-q] [<tree-ish>] [--] <pathspec>…​
git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>…​]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

説明

最初の3つの形式では、<tree-ish>からインデックスにエントリをコピーします。最後の形式では、現在のブランチのヘッド (HEAD) を<commit>に設定し、必要に応じてインデックスとワーキングツリーを一致するように変更します。<tree-ish>/<commit>は、すべての形式でデフォルトでHEADになります。

git reset [-q] [<tree-ish>] [--] <pathspec>...
git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]

これらの形式は、<pathspec>に一致するすべてのパスのインデックスエントリを、<tree-ish>の状態にリセットします。(ワーキングツリーや現在のブランチには影響しません。)

これは、git reset <pathspec>git add <pathspec>の反対であることを意味します。このコマンドは、git restore [--source=<tree-ish>] --staged <pathspec>... と同等です。

git reset <pathspec>を実行してインデックスエントリを更新した後、git-restore[1]を使用してインデックスの内容をワーキングツリーにチェックアウトできます。あるいは、git-restore[1]を使用し、--sourceでコミットを指定することで、コミットの内容をパスからインデックスとワーキングツリーに一度にコピーできます。

git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]

インデックスと<tree-ish> (デフォルトはHEAD) の差分からハンクをインタラクティブに選択します。選択されたハンクはインデックスに逆方向に適用されます。

これは、git reset -pgit add -pの反対、つまりハンクを選択的にリセットするために使用できることを意味します。--patchモードの操作方法については、git-add[1]の「インタラクティブモード」セクションを参照してください。

git reset [<mode>] [<commit>]

この形式は、現在のブランチのヘッドを<commit>にリセットし、<mode>に応じてインデックス (<commit>のツリーにリセット) とワーキングツリーを更新する場合があります。操作の前に、ORIG_HEADは現在のブランチの先端に設定されます。<mode>が省略された場合、デフォルトは--mixedになります。<mode>は次のいずれかである必要があります。

--soft

インデックスファイルもワーキングツリーも一切変更しません (ただし、すべてのモードと同様に、ヘッドを<commit>にリセットします)。これにより、git statusが示すように、すべての変更されたファイルが「コミット対象の変更」として残されます。

--mixed

インデックスはリセットしますが、ワーキングツリーはリセットしません (つまり、変更されたファイルは保持されますが、コミット対象としてマークされません) 。更新されていないものを報告します。これがデフォルトのアクションです。

-Nが指定された場合、削除されたパスはintent-to-add (追加予定) としてマークされます (git-add[1]を参照)。

--hard

インデックスとワーキングツリーをリセットします。<commit>以降にワーキングツリー内の追跡されているファイルに加えられた変更はすべて破棄されます。追跡されているファイルを書き込むのを妨げる、追跡されていないファイルまたはディレクトリは単純に削除されます。

--merge

インデックスをリセットし、<commit>HEADの間で異なるワーキングツリー内のファイルを更新しますが、インデックスとワーキングツリーの間で異なるファイル (つまり、まだ追加されていない変更があるファイル) は保持します。<commit>とインデックスの間で異なるファイルにステージされていない変更がある場合、リセットは中止されます。

言い換えれば、--mergegit read-tree -u -m <commit>のようなことを行いますが、未マージのインデックスエントリを引き継ぎます。

--keep

インデックスエントリをリセットし、<commit>HEADの間で異なるワーキングツリー内のファイルを更新します。<commit>HEADの間で異なるファイルにローカルな変更がある場合、リセットは中止されます。

--[no-]recurse-submodules

ワーキングツリーが更新される際、--recurse-submodulesを使用すると、スーパープロジェクトに記録されたコミットに従って、すべてのアクティブなサブモジュールのワーキングツリーも再帰的にリセットされ、サブモジュールのHEADはそのコミットでデタッチされた状態に設定されます。

これら3つのコマンドの違いについては、git[1]の「リセット、リストア、リバート」を参照してください。

オプション

-q
--quiet

静かに実行し、エラーのみを報告します。

--refresh
--no-refresh

mixed resetの後にインデックスをリフレッシュします。デフォルトで有効です。

--pathspec-from-file=<file>

パススペックはコマンドライン引数ではなく<file>で渡されます。<file>が正確に-の場合、標準入力が使用されます。パススペック要素はLFまたはCR/LFで区切られます。パススペック要素は設定変数core.quotePathについて説明されているように引用符で囲むことができます (git-config[1]を参照)。--pathspec-file-nulおよびグローバルな--literal-pathspecsも参照してください。

--pathspec-file-nul

--pathspec-from-fileとの組み合わせでのみ意味があります。パススペック要素はNUL文字で区切られ、他のすべての文字はリテラルとして扱われます (改行や引用符を含む)。

--

これ以降の引数をオプションとして解釈しません。

<pathspec>...

操作の影響を受けるパスを制限します。

詳細については、gitglossary[7]pathspecエントリを参照してください。

追加を元に戻す
$ edit                                     (1)
$ git add frotz.c filfre.c
$ mailx                                    (2)
$ git reset                                (3)
$ git pull git://info.example.com/ nitfol  (4)
  1. 作業中に、これらのファイルへの変更がうまくまとまっていることを見つけました。他のファイルや変更に集中したいので、git diffを実行するときにこれらの変更を見たくありません。

  2. 誰かがプルを要求し、その変更はマージする価値があるようです。

  3. しかし、すでにインデックスを汚してしまっています (つまり、インデックスがHEADコミットと一致しません)。しかし、これから行うプルがfrotz.cfilfre.cに影響しないことを知っているので、これら2つのファイルのインデックス変更を元に戻します。ワーキングツリー内の変更はそのまま残ります。

  4. その後、プルとマージを行い、frotz.cfilfre.cの変更をワーキングツリーに残しておくことができます。

コミットを元に戻してやり直す
$ git commit ...
$ git reset --soft HEAD^      (1)
$ edit                        (2)
$ git commit -a -c ORIG_HEAD  (3)
  1. これは、コミットしたばかりのものが不完全であること、コミットメッセージのスペルを間違えたこと、またはその両方を思い出した場合によく行われます。「reset」前のワーキングツリーの状態をそのまま残します。

  2. ワーキングツリーのファイルを修正します。

  3. 「reset」は古いヘッドを.git/ORIG_HEADにコピーします。そのログメッセージから始めてコミットをやり直します。メッセージをさらに編集する必要がない場合は、代わりに-Cオプションを指定できます。

    git-commit[1]--amendオプションも参照してください。

コミットを元に戻し、トピックブランチにする
$ git branch topic/wip          (1)
$ git reset --hard HEAD~3       (2)
$ git switch topic/wip          (3)
  1. いくつかのコミットをしましたが、それらがmasterブランチに入れるには時期尚早であることに気づきました。それらをトピックブランチでさらに磨き続けたいので、現在のHEADからtopic/wipブランチを作成します。

  2. マスターブランチを巻き戻して、それらの3つのコミットを削除します。

  3. topic/wipブランチに切り替えて作業を続けます。

コミットを永久に元に戻す
$ git commit ...
$ git reset --hard HEAD~3   (1)
  1. 最後の3つのコミット (HEADHEAD^、およびHEAD~2) は悪く、二度と見たくありません。これらのコミットをすでに他の誰かに渡している場合は、これを行ってはいけません。(これを行うことの意味については、git-rebase[1]の「アップストリームのリベースからの復旧」セクションを参照してください。)

マージまたはプルを元に戻す
$ git pull                         (1)
Auto-merging nitfol
CONFLICT (content): Merge conflict in nitfol
Automatic merge failed; fix conflicts and then commit the result.
$ git reset --hard                 (2)
$ git pull . topic/branch          (3)
Updating from 41223... to 13134...
Fast-forward
$ git reset --hard ORIG_HEAD       (4)
  1. アップストリームからの更新を試みた結果、多くの競合が発生しました。今はマージに多くの時間を費やす準備ができていなかったので、後で行うことにしました。

  2. 「pull」はマージコミットを作成していないため、git reset --hard (git reset --hard HEADの同義語) は、インデックスファイルとワーキングツリーの混乱を解消します。

  3. トピックブランチを現在のブランチにマージし、高速フォワードが発生しました。

  4. しかし、トピックブランチはまだ一般公開の準備ができていないと判断しました。「pull」または「merge」は常に現在のブランチの元の先端をORIG_HEADに残すため、それにハードリセットすると、インデックスファイルとワーキングツリーがその状態に戻り、ブランチの先端がそのコミットにリセットされます。

汚れたワーキングツリー内でのマージまたはプルを元に戻す
$ git pull                         (1)
Auto-merging nitfol
Merge made by recursive.
 nitfol                |   20 +++++----
 ...
$ git reset --merge ORIG_HEAD      (2)
  1. ワーキングツリーにローカルな変更がある場合でも、他のブランチの変更がそれらと重複しないことがわかっている場合は、安全にgit pullと言えます。

  2. マージの結果を検査した後、他のブランチの変更が不満であると判明するかもしれません。git reset --hard ORIG_HEADを実行すると元に戻ることができますが、ローカルな変更は破棄されます。これは望ましくありません。git reset --mergeはローカルな変更を保持します。

中断されたワークフロー

大規模な変更の途中で緊急の修正要求によって中断されたとします。ワーキングツリー内のファイルはまだコミットできる状態ではありませんが、迅速なバグ修正のために他のブランチに移動する必要があります。

$ git switch feature  ;# you were working in "feature" branch and
$ work work work      ;# got interrupted
$ git commit -a -m "snapshot WIP"                 (1)
$ git switch master
$ fix fix fix
$ git commit ;# commit with real log
$ git switch feature
$ git reset --soft HEAD^ ;# go back to WIP state  (2)
$ git reset                                       (3)
  1. このコミットは破棄されるため、使い捨てのログメッセージでも構いません。

  2. これにより、WIPコミットがコミット履歴から削除され、ワーキングツリーはスナップショットを作成する直前の状態に設定されます。

  3. この時点でもインデックスファイルには、snapshot WIPとしてコミットしたすべてのWIP変更が残っています。これにより、インデックスが更新され、WIPファイルが未コミットとして表示されます。

    git-stash[1]も参照してください。

インデックス内の単一ファイルをリセットする

ファイルをインデックスに追加したが、後でコミットに追加したくないと判断したとします。git resetを使用すると、変更を保持したままインデックスからファイルを削除できます。

$ git reset -- frotz.c                      (1)
$ git commit -m "Commit files in index"     (2)
$ git add frotz.c                           (3)
  1. これにより、ファイルはワーキングディレクトリに残されたまま、インデックスから削除されます。

  2. これにより、インデックス内の他のすべての変更がコミットされます。

  3. ファイルを再度インデックスに追加します。

いくつかの前のコミットを破棄しつつ、ワーキングツリーの変更を保持する

何か作業をしていてコミットし、さらに少し作業を続けたが、現在のワーキングツリーにあるものは以前コミットしたものとは関係のない別のブランチにあるべきだと考えた場合。新しいブランチを開始し、ワーキングツリーの変更を保持したままリセットできます。

$ git tag start
$ git switch -c branch1
$ edit
$ git commit ...                            (1)
$ edit
$ git switch -c branch2                     (2)
$ git reset --keep start                    (3)
  1. これはbranch1での最初の編集をコミットします。

  2. 理想的には、branch2を作成して切り替えたとき (つまり、git switch -c branch2 start) に、以前のコミットが新しいトピックに属さないことに気づいたかもしれませんが、完璧な人はいません。

  3. しかし、branch2に切り替えた後、reset --keepを使って不要なコミットを削除することができます。

コミットを複数のコミットに分割する

論理的に分離された多くの変更を作成し、それらをまとめてコミットしたとします。その後、各論理チャンクを独自のコミットに関連付けた方が良いと判断しました。git resetを使用して、ローカルファイルの内容を変更せずに履歴を巻き戻し、その後、git add -pを順次使用して、各コミットに含めるハンクをインタラクティブに選択し、git commit -cを使用してコミットメッセージを事前に設定できます。

$ git reset -N HEAD^                        (1)
$ git add -p                                (2)
$ git diff --cached                         (3)
$ git commit -c HEAD@{1}                    (4)
...                                         (5)
$ git add ...                               (6)
$ git diff --cached                         (7)
$ git commit ...                            (8)
  1. まず、履歴を1コミット巻き戻して元のコミットを削除しますが、ワーキングツリーはすべての変更を残します。-Nは、HEADで追加された新しいファイルが引き続きマークされるようにし、git add -pがそれらを見つけられるようにします。

  2. 次に、git add -p機能を使用して、インタラクティブに差分ハンクを追加します。これにより、各差分ハンクについて順次質問され、「はい、これを含める」、「いいえ、含めない」などの簡単なコマンド、または非常に強力な「編集」機能を使用できます。

  3. 含めたいハンクに満足したら、git diff --cachedを使用して、最初のコミット用に準備されたものを確認する必要があります。これは、インデックスに移動され、コミットされようとしているすべての変更を示します。

  4. 次に、インデックスに保存されている変更をコミットします。-cオプションは、最初のコミットで開始した元のメッセージからコミットメッセージを事前に設定することを指定します。これにより、再入力の手間が省けます。HEAD@{1}は、元のリセットコミットの前にHEADがあったコミット (1変更前) の特殊な表記です。git-reflog[1]で詳細を参照してください。他の有効なコミット参照も使用できます。

  5. 手順2〜4を複数回繰り返して、元のコードを任意の数のコミットに分割できます。

  6. これで、多くの変更を独自のコミットに分割し、残りのコミットされていない変更をすべて選択するために、もはやgit addのパッチモードを使用しないかもしれません。

  7. もう一度、含めたいものが含まれていることを確認します。後でコミットする残りの変更がgit diffに表示されないことも確認したいかもしれません。

  8. そして最後に、最終コミットを作成します。

考察

以下の表は、

git reset --option target

ファイルをさまざまなリセットオプションで別のコミット (target) にリセットした場合に何が起こるかを示しています。

これらの表では、ABCDはファイルの状態が異なることを意味します。例えば、最初の表の最初の行は、ワーキングツリーのファイルがAの状態、インデックスがBの状態、HEADCの状態、ターゲットがDの状態である場合、git reset --soft targetを実行すると、ワーキングツリーのファイルはAの状態、インデックスはBの状態のままになることを意味します。そして、HEAD (現在のブランチの先端、もしある場合) をtarget (ファイルがDの状態である) にリセット (つまり移動) します。

working index HEAD target         working index HEAD
----------------------------------------------------
 A       B     C    D     --soft   A       B     D
			  --mixed  A       D     D
			  --hard   D       D     D
			  --merge (disallowed)
			  --keep  (disallowed)
working index HEAD target         working index HEAD
----------------------------------------------------
 A       B     C    C     --soft   A       B     C
			  --mixed  A       C     C
			  --hard   C       C     C
			  --merge (disallowed)
			  --keep   A       C     C
working index HEAD target         working index HEAD
----------------------------------------------------
 B       B     C    D     --soft   B       B     D
			  --mixed  B       D     D
			  --hard   D       D     D
			  --merge  D       D     D
			  --keep  (disallowed)
working index HEAD target         working index HEAD
----------------------------------------------------
 B       B     C    C     --soft   B       B     C
			  --mixed  B       C     C
			  --hard   C       C     C
			  --merge  C       C     C
			  --keep   B       C     C
working index HEAD target         working index HEAD
----------------------------------------------------
 B       C     C    D     --soft   B       C     D
			  --mixed  B       D     D
			  --hard   D       D     D
			  --merge (disallowed)
			  --keep  (disallowed)
working index HEAD target         working index HEAD
----------------------------------------------------
 B       C     C    C     --soft   B       C     C
			  --mixed  B       C     C
			  --hard   C       C     C
			  --merge  B       C     C
			  --keep   B       C     C

git reset --mergeは、競合するマージからリセットする場合に使用することを意図しています。マージ操作は、マージに含まれるワーキングツリーファイルが開始前にインデックスに対してローカルな変更を持たず、結果をワーキングツリーに書き込むことを保証します。したがって、インデックスとターゲットの間、およびインデックスとワーキングツリーの間にいくつかの違いがある場合、それはマージ操作が競合で失敗した後に残した状態からリセットしていないことを意味します。そのため、この場合は--mergeオプションを許可しません。

git reset --keepは、ワーキングツリーの変更を保持しながら、現在のブランチの最後のコミットの一部を削除する場合に使用することを意図しています。削除したいコミットの変更と保持したいワーキングツリーの変更の間に競合が発生する可能性がある場合、リセットは許可されません。そのため、ワーキングツリーとHEADの間、およびHEADとターゲットの間に両方の変更がある場合は許可されません。安全のため、未マージのエントリがある場合も許可されません。

以下の表は、未マージのエントリがある場合に何が起こるかを示しています。

working index HEAD target         working index HEAD
----------------------------------------------------
 X       U     A    B     --soft  (disallowed)
			  --mixed  X       B     B
			  --hard   B       B     B
			  --merge  B       B     B
			  --keep  (disallowed)
working index HEAD target         working index HEAD
----------------------------------------------------
 X       U     A    A     --soft  (disallowed)
			  --mixed  X       A     A
			  --hard   A       A     A
			  --merge  A       A     A
			  --keep  (disallowed)

Xは任意の状態を意味し、Uは未マージのインデックスを意味します。

GIT

git[1]スイートの一部

scroll-to-top