git add してしまったファイルを取り消しするgit コマンドです。
今までなんとなくできていたのですが、ぼんやりとした理解だったので、今回は深掘りしてしっかり理解したので、まとめました。
Table of Content
git add したファイルを取り消すコマンド
まずは、addを取り消すgitコマンドの紹介から。
git addした全てのファイルを取り消し
git add したファイルの変更内容を、インデックスから削除します。git resetに、HEADと指定するか、もしくは引数なしで、デフォルトでHEADを指定した事になります。
1 2 3 4 5 |
// git add したファイルをインデックスから削除 git reset // 上と同義 git reset HEAD |
git addした特定のファイルを取り消し
特定のファイルのみ、変更内容をインデックスから削除します。
1 2 3 4 5 |
// git add したファイルをインデックスから削除 git reset <file name> // 上と同義 git reset HEAD <file name> |
これらの操作を「git addの取り消し」と呼ぶよりは、「インデックスを、HEADのコミット状態にリセットする」と言った方が誤解が少なく、イメージもしやすいかもしれません。
以下、git resetについて詳しく見ていきます。
git reset についてちゃんと理解する
git reset は何をしているか?
git reset は「現在のブランチの先頭(とブランチ履歴)」と「インデックスの状態」を、指定されたコミットに強制的に書き換えます。
HEADは通常、現在のブランチの先頭コミットを参照していますので、「git reset HEAD」と、HEADの指している状態へのリセットに施す事により、インデックスの状態がコミットのと同じ状態になる、すなわち、もとに戻る、というわけです。
(実際は「git reset」とコミット指定を省略すると、デフォルトでHEADとなります。)
※git reset(モード指定なし)は作業ツリーには何もしません。モードの詳細は後述。
git resetは「git addの取り消し」ではない
注意が必要なのが、例えば「最後のcommitから2回目のaddだった時、1回目のaddは、commit せずにindexにいれておいただけ」という1回目の変更含めて、すべてリセットされてしまいます。
本当の意味での、「git addコマンドの取り消し」はgitでは不可能です。
git では一般的に、コミットしたり、stashしていない変更内容は、一度失われると取り返せません。
HEAD以外のコミットにresetする
引数で、HEAD以外のコミットを指定します。動作仕様の通り、ブランチの先頭が指定のされたコミットに移動します。
git reset <commit>
動作仕様どおり、今いるブランチのHEADが指定コミットにリセットされ、インデックスも強制的に書き換わります。
git reset <commit> <file_name>
git reset <commit> <file_name>とファイル名やパスを指定すると、上記のようなHEADの移動は起きず、特定のファイルのインデックスがリセットされます。
この原理で、「git reset <commit> . 」とドットを使ってすべてのファイルを指定すると、HEADをそのままにして、インデックスのファイルをすべてそのコミットに合わせる事になります。
1 2 3 |
// 正確には同義ではないが、実質同じ効果 git reset HEAD git reset HEAD . |
このように、ブランチを指定するの、ファイル指定するので、現在のブランチの歴史が書き換わるかどうか?の振る舞いが異なります。
この動きは「git checkout」のときと似ています。git checkoutでは、「ブランチを切り替えるかどうか」の振る舞いが変わりました。
参考リンク:gitでリモートのブランチをcheckoutして、作業する方法
git reset のモード
git reset には代表的な3種類のモードがありました。(ほんとはもっとありますが)
git resetのモード
モード指定 | 動作 |
git reset –soft | 現在のbranchの先頭だけをリセット。(インデックスはそのまま) |
git reset git reset –mixed |
現在のbranchの先頭と、インデックスをリセット |
git reset –hard | 現在のbranchの先頭、インデックスも作業ツリーも全部リセット |
冒頭の取り消し操作は、引数なしのmixedモードです。「git reset 」により、インデックスとブランチの先頭をリセットします。
混乱のなきよう、もしあなたがbranchの先頭(=HEAD)で作業しているならば、今いるブランチの先頭は、「git reset」コマンドによって変更されることはありません。(HEADをHEADにリセットしている)
git reset –softはいつ使うの?
最新のコミットの内容をちょっとだけ修正したい時にgit reset –soft HEAD^ とすると、直前のgit インデックスには最新の変更を取り出して、それがまだコミットされていない状態に戻れます。
例えば、もし「デバッグコード削除し忘れ」の修正であれば、あとはコードを削除してgit commit を実行するだけでコミットをやり直せます。
それ以外の用途は、あまり思いつきません。
git reset –mixedはいつ使うの?
上述の通りで、git reset HEADで、addのやり直しなど、コミットを作っている最中に使うかもしれません。
git rest –hard はいつ使うの?
例えば、「ローカルブランチをリモートブランチで強制上書きする」などする時に、一撃必殺技的に使うことが多いです。ローカルブランチの歴史もろとも、不要なものを全部消し去って、特定の基準点に一気に帰りたい時、ということだと思います。
git add の取り消しに関する参考
resetもだいたいマニュアルには書いてあります。
うまくgit addを取り消しできたでしょうか。
以上です。