Git入門:バージョン管理のきほん
コミットを取り消す(reset の 3 モード)
この回でやること
git reset の --soft / --mixed / --hard を比較して、コミットを取り消す方法を学びます。手元だけで完結する巻き戻し方と --hard の危険さを理解しましょう。
- 読む 約 8 分
コミットしたあとで、やり直したくなる
「とりあえずコミット」という雑なメッセージのまま記録してしまった。細かく分けすぎたので 3 つを 1 つにまとめたい。どれもコミットしたあとで気づきます。
git reset は、そのやり直しのためのコマンドです。やっているのは、現在地を示す HEAD を前のコミットに付け替えることだけです。
プレーンテキスト
reset 前 A --- B --- C ← HEAD
reset 後 A --- B ← HEAD
C (たどれなくなる)C が削除されるわけではありません。たどる道が切れて、git log に出なくなるだけです。
このコマンドは、まだ誰とも共有していない手元だけの履歴に使います。すでに git push で送ったものに使うと、自分の履歴だけが短くなって相手と食い違います。公開済みのものを打ち消すのは git revert の担当です。
巻き戻す深さを 3 段階から選ぶ
3 つのモードは別々の機能ではありません。「どこまで巻き込むか」という 1 本の目盛りです。 目盛りを 1 つ上げるごとに、手元に残るものが減ります。
| 打つもの | 巻き戻る範囲 | 手元に残るもの |
|---|---|---|
git reset --soft HEAD~1 | コミットだけ | ステージに載ったまま全部 |
git reset HEAD~1 | コミットとステージ | 編集した中身 |
git reset --hard HEAD~1 | 作業中のファイルまで | 何も残らない(未コミットの編集も消える) |
HEAD~1 は 1 つ前、HEAD~3 なら 3 つ前です。モードを省くと真ん中の動きになります。
いちばん浅い --soft は、メッセージを言い直したいときに使います。
ターミナル
$ git reset --soft HEAD~1
$ git status
Changes to be committed:
modified: src/app.js
$ git commit -m "ログイン失敗時のエラーメッセージを追加"ファイルの中身は 1 バイトも変わっていません。動いたのは現在地だけなので、何度でもやり直せます。--soft HEAD~3 としてから 1 回コミットすれば、細かすぎた 3 件を 1 つにまとめられます。
真ん中の git reset HEAD~1 は、ステージも解きます。何をコミットするか選び直せる状態に戻るので、1 つのコミットを 2 つに分けたいときに向いています。3 つのうち、いちばん出番が多いモードです。
--hard は、書いたファイルごと消える
いちばん深い --hard で失うものを、先に挙げます。取り消したコミットの中身が、手元のファイルからも消えます。さらに、そのとき編集中だった、まだ git add すらしていない別の作業も一緒に消えます。確認は出ません。
コミット済みだったものは、しばらくは git reflog からたどって取り戻せます。しかし一度もコミットしていない編集は、どこにも残りません。
だから、打つ前に必ずこの 1 行を読みます。
ターミナル
$ git status
On branch main
Changes not staged for commit:
modified: src/other-feature.jsここに何か並んでいたら、それが消える対象です。関係ない作業が混ざっているなら、先に git stash で退避するか、別にコミットします。何も並んでいないと確かめてから、はじめて --hard に戻り先を付けて実行してください。
そもそも、目的が「コミットをやり直す」ことなら --soft か真ん中で足ります。「なんだか状態が変だから綺麗にしよう」という使い方が、いちばん事故を起こします。
git resetは現在地を前のコミットに付け替える。コミットは消えず、たどれなくなるだけ- 3 つのモードは「どこまで巻き込むか」の目盛り。コミットだけ、ステージも、作業中のファイルも
--hardは未コミットの編集ごと消える。git statusが空だと確かめてから打つ- 共有済みの履歴には使わない。そちらは
git revertの担当