変更の取り消し
コミットした後に間違いに気づいたり、作業をやり直したいことはよくあります。
git commit --amend・
git reset
を正しく使えるようになりましょう。
git commit --amend — 直前のコミットを修正する
「コミットメッセージを typo した」「ファイルを追加し忘れた」ときに使います。 push 前の、まだ自分しか持っていないコミットにのみ使うのが安全です。
メッセージだけ直す
# 直前のコミットメッセージを上書き $ git commit --amend -m "正しいメッセージ"
ファイルを追加して修正する
# 追加ファイルをステージしてから $ git add 追加したいファイル $ git commit --amend --no-edit # --no-edit でメッセージはそのまま
amend 後に push するとき — git push --force-with-lease
--amend はコミット履歴を書き換えるため、
push 済みの場合は通常の git push が拒否されます。
--force-with-lease を使うと、
他の人が新たに push していないことを確認してから強制 push できます。
# --force ではなく --force-with-lease を使う(より安全) $ git push --force-with-lease # 他の人が push していた場合はエラーになる(意図せず上書きしない) ! [rejected] feature/login -> feature/login (stale info)
注意:main など共有ブランチへの force push はチーム全員に影響します。 自分だけが使う feature ブランチの push 直後の修正にのみ使うようにしましょう。
git reset — コミットを取り消す
git reset はコミット履歴を指定した地点まで巻き戻します。
オプションによってファイルの変更が残るかどうかが変わります。
--soft コミットだけ取り消す
- 変更ファイル ✓ 残る
- ステージング ✓ 残る
コミットメッセージを書き直したいときなど。ファイルの変更はそのまま残る。
--mixed(デフォルト) コミット+ステージを取り消す
- 変更ファイル ✓ 残る
- ステージング ✗ 取り消し
git add をやり直したいときに。ファイルの内容は消えない。
--hard 変更ごとすべて取り消す
- 変更ファイル ✗ 削除!
- ステージング ✗ 削除!
作業をまるごとなかったことにする。取り消せないので注意。
# 直前のコミットだけ取り消す(ファイルはステージング済みのまま残る) $ git reset --soft HEAD~1 # 直前のコミットとステージングを取り消す(ファイルは残る) $ git reset HEAD~1 # --mixed はデフォルトなので省略可 # 直前のコミットも変更もすべて消す(元に戻せない!) $ git reset --hard HEAD~1 # HEAD~1 は「1つ前のコミット」。HEAD~2 で2つ前まで戻ることもできる
push 済みのコミットに reset してはいけない
git reset は履歴を書き換えます。
既に push 済みのコミットに使うと、チームメンバーのリポジトリと履歴が食い違い大きなトラブルになります。
push 済みの変更を取り消すには次の git revert を使いましょう。
git revert — push 済みコミットを安全に取り消す
git revert は
指定したコミットの内容を打ち消す新しいコミットを作ります。
履歴を書き換えないため、push 済みのブランチでも安全に使えます。
# 現在の履歴を確認 $ git log --oneline a1b2c3d (HEAD -> main) feat: バグを含む変更を追加 e4f5g6h feat: ログイン機能を追加 7h8i9j0 feat: トップページを追加 # a1b2c3d を打ち消すコミットを作成(履歴は消えない) $ git revert a1b2c3d [main f1g2h3i] Revert "feat: バグを含む変更を追加" 1 file changed, 5 deletions(-) $ git log --oneline f1g2h3i (HEAD -> main) Revert "feat: バグを含む変更を追加" a1b2c3d feat: バグを含む変更を追加 ← 削除されず打ち消しコミットが追加される e4f5g6h feat: ログイン機能を追加
reset と revert の使い分け
git reset(push 前のみ)
- • 履歴を書き換える(コミットが消える)
- • push 済みのブランチには使わない
- • ローカルの作業をやり直したいとき
git revert(push 後も使える)
- • 打ち消しコミットを新たに作る
- • 履歴が壊れないのでチーム開発でも安全
- • push 済みの変更を取り消したいとき
git stash — 作業を一時退避する
コミットしていない変更がある状態で別のブランチに切り替えたいとき、
git stash で
変更を一時的に退避できます。後から
git stash pop で取り出せます。
# 作業中のファイルがある状態 $ git status Changes not staged for commit: modified: index.html # 変更を一時退避(コミットせずに保存) $ git stash Saved working directory and index state WIP on main: a1b2c3d feat: ... # ブランチを切り替えて作業...(ワーキングツリーはクリーンな状態) $ git switch feature/hotfix # 元のブランチに戻り、退避した変更を取り出す $ git switch main $ git stash pop On branch main Changes not staged for commit: modified: index.html ← 変更が戻ってきた
git stash 変更を退避(スタックに積む)
git stash pop 直近の退避を取り出す(スタックから削除)
git stash list 退避済み一覧を表示
どれを使えばいい?
git commit --amend -m "正しいメッセージ" git add ファイル && git commit --amend --no-edit git reset HEAD~1(変更はそのまま残る) git reset --hard HEAD~1(危険:取り消せない) git revert コミットID(打ち消しコミットを追加) git stash → 切り替え作業 → git stash pop