TAKASHI YAMASHINA software engineer

git revertとgit resetの違い

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を使う場面

  1. 既にpushしたコミットを取り消す
bash
# リモートに既にpush済み
git revert abc1234
git push origin main  # 問題なくpushできる
  1. 本番環境にデプロイ済みの変更を取り消す
bash
# 本番で問題が発生したコミットを打ち消す
git revert HEAD
git push origin main
  1. 他の開発者が既にpullした可能性がある
bash
# チームで共有しているブランチ
git revert abc1234
git push origin main

git resetを使う場面

  1. まだpushしていないコミットを削除
bash
# ローカルのみのコミットを削除
git reset --hard HEAD~1
  1. コミットメッセージを修正
bash
# 直前のコミットをやり直す
git reset --soft HEAD~1
git commit -m "正しいメッセージ"
  1. 複数のコミットを1つにまとめる
bash
# 直近3つのコミットを1つにまとめる
git reset --soft HEAD~3
git commit -m "まとめたコミットメッセージ"
  1. ステージングを取り消す
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  # 変更はステージングに残る