git revertは過去のコミットを打ち消す新しいコミットを作成し、git resetはコミット履歴自体を削除します。共有済みのブランチではgit revertを使い、ローカルのみのコミットにはgit resetを使います。
git revertの使い方
コミットを打ち消す新しいコミットを作成します。元のコミットは履歴に残ります。
bash
# 直前のコミットを打ち消す
git revert HEAD
# 特定のコミットを打ち消す
git revert abc1234
# 複数のコミットを打ち消す
git revert abc1234..def5678
実行例
bash
# 現在の履歴
* c3d4e5 (HEAD -> main) Add feature C
* b2c3d4 Add feature B # このコミットを打ち消したい
* a1b2c3 Add feature A
# feature Bを打ち消す
git revert b2c3d4
# 結果:打ち消しのコミットが追加される
* f6g7h8 (HEAD -> main) Revert "Add feature B"
* c3d4e5 Add feature C
* b2c3d4 Add feature B # 履歴に残る
* a1b2c3 Add feature A
git resetの使い方
コミット履歴を指定した位置まで戻します。コミットを履歴から削除します。
bash
# 直前のコミットを削除(変更内容は作業ディレクトリに残す)
git reset --soft HEAD~1
# 直前のコミットを削除(変更内容はステージングエリアに残す)
git reset --mixed HEAD~1
# 直前のコミットを完全に削除(変更内容も削除)
git reset --hard HEAD~1
# 特定のコミットまで戻る
git reset --hard abc1234
実行例
bash
# 現在の履歴
* c3d4e5 (HEAD -> main) Add feature C
* b2c3d4 Add feature B # ここまで戻りたい
* a1b2c3 Add feature A
# feature Cのコミットを削除
git reset --hard b2c3d4
# 結果:feature Cのコミットが履歴から消える
* b2c3d4 (HEAD -> main) Add feature B
* a1b2c3 Add feature A
resetの3つのモード
--soft: コミットだけを取り消す
bash
git reset --soft HEAD~1
- コミット履歴から削除
- 変更内容はステージングエリアに残る
- すぐに再コミット可能
--mixed(デフォルト): コミットとステージングを取り消す
bash
git reset --mixed HEAD~1
# または
git reset HEAD~1
- コミット履歴から削除
- ステージングも解除
- 変更内容は作業ディレクトリに残る
--hard: すべてを取り消す
bash
git reset --hard HEAD~1
- コミット履歴から削除
- ステージングも解除
- 変更内容も完全に削除(危険)
使い分け
git revertを使う場面
- 既にpushしたコミットを取り消す
bash
# リモートに既にpush済み
git revert abc1234
git push origin main # 問題なくpushできる
- 本番環境にデプロイ済みの変更を取り消す
bash
# 本番で問題が発生したコミットを打ち消す
git revert HEAD
git push origin main
- 他の開発者が既にpullした可能性がある
bash
# チームで共有しているブランチ
git revert abc1234
git push origin main
git resetを使う場面
- まだpushしていないコミットを削除
bash
# ローカルのみのコミットを削除
git reset --hard HEAD~1
- コミットメッセージを修正
bash
# 直前のコミットをやり直す
git reset --soft HEAD~1
git commit -m "正しいメッセージ"
- 複数のコミットを1つにまとめる
bash
# 直近3つのコミットを1つにまとめる
git reset --soft HEAD~3
git commit -m "まとめたコミットメッセージ"
- ステージングを取り消す
bash
# ファイルのステージングを解除
git reset HEAD <file>
なぜrevertの方が安全か
1. 履歴を改変しない
git revertは履歴に新しいコミットを追加するだけで、既存の履歴は変更しません。
bash
# revert: 履歴を追加(安全)
A -- B -- C -- D (revert C)
↑
履歴はそのまま
# reset: 履歴を削除(危険)
A -- B -- C
↑
Cが消える
2. 他の開発者に影響しない
git resetで履歴を削除すると、既にその履歴をpullした他の開発者のリポジトリと矛盾が生じます。
bash
# 開発者Aがresetを実行
git reset --hard HEAD~1
git push --force # 強制push(危険)
# 開発者Bのリポジトリは古い履歴を持っている
# → コンフリクトや混乱が発生
3. 変更の記録が残る
git revertを使うと、「なぜその変更を取り消したか」の記録が履歴に残ります。
bash
git revert abc1234 -m "本番環境でエラーが発生したため機能Xを無効化"
resetを使う際の注意点
共有ブランチでは使わない
bash
# ❌ 危険:共有ブランチでreset
git checkout main
git reset --hard HEAD~1
git push --force # 他の開発者に影響
# ✅ 安全:共有ブランチではrevert
git checkout main
git revert HEAD
git push # 通常のpush
--hardは取り消せない
git reset --hardで削除した変更は基本的に復元できません。
bash
# ❌ 危険:変更が完全に失われる
git reset --hard HEAD~1
# ✅ 安全:変更を残す
git reset --soft HEAD~1 # または --mixed
force pushが必要になる
共有ブランチでresetを使うと、force pushが必要になります。
bash
git reset --hard HEAD~1
git push # エラー:履歴が矛盾
git push --force # 危険:他の開発者の履歴を破壊
実践的なワークフロー
コミットをやり直したい(ローカルのみ)
bash
# コミットを取り消して、変更内容は残す
git reset --soft HEAD~1
# ファイルを修正
vim file.txt
# 再度コミット
git add file.txt
git commit -m "修正したコミットメッセージ"
本番環境の問題を緊急で取り消す
bash
# 問題のあるコミットを特定
git log
# revertで打ち消す
git revert abc1234
# すぐにpushして本番に反映
git push origin main
ローカルの作業をリセット
bash
# すべての変更を破棄してリモートと同じ状態に戻す
git fetch origin
git reset --hard origin/main
よくある間違い
resetで削除したコミットをpushしようとする
bash
git reset --hard HEAD~1
git push # エラー:リモートの方が進んでいる
# 解決策:revertを使う、またはforce push(危険)
revertとresetを混同する
bash
# ❌ 間違い:共有ブランチでreset
git reset --hard HEAD~1
# ✅ 正しい:共有ブランチではrevert
git revert HEAD
resetのモードを間違える
bash
# 変更内容を残したいのに--hardを使う
git reset --hard HEAD~1 # 変更が消える!
# 正しい:--softまたは--mixed
git reset --soft HEAD~1 # 変更はステージングに残る