メインコンテンツへスキップ
レッスン 10 / 15推定時間: 25

履歴の書き換えと危険性

reset、revert、amendを使いこなし、履歴を適切に管理する方法と、その危険性について学びましょう

このレッスンの学習目標

  • reset、revert、amendの違いを理解する
  • 各コマンドの適切な使用場面を判断できる
  • 履歴書き換えの危険性と回避方法を理解する

なぜ履歴を変更するのか?

Gitの履歴を変更する理由は様々です:

🧹 履歴の整理

  • 「意味のないコミットメッセージを修正したい」
  • 「細かすぎるコミットをまとめたい」
  • 「間違った変更を取り消したい」

🔐 セキュリティ

  • 「パスワードを誤ってコミットしてしまった」
  • 「機密情報を履歴から完全に削除したい」

🎯 クリーンな履歴

  • 「プルリクエスト前に履歴を整理したい」
  • 「実験的なコミットを削除したい」

主要な履歴変更コマンド

1. git commit --amend(直前のコミット修正)

最も安全で一般的な履歴変更方法です。

# コミットメッセージの修正
git commit --amend -m "新しいコミットメッセージ"

# ファイルの追加し忘れ
git add forgotten-file.js
git commit --amend --no-edit

# コミット内容とメッセージの両方を修正
git add modified-file.js
git commit --amend

2. git revert(変更の打ち消し)

既存のコミットを打ち消す新しいコミットを作成します。履歴は残るため安全です。

# 特定のコミットを打ち消し
git revert abc1234

# 複数のコミットを打ち消し
git revert abc1234..def5678

# マージコミットを打ち消し
git revert -m 1 merge-commit-hash

3. git reset(履歴の巻き戻し)

コミットを取り消し、履歴を巻き戻します。3つのモードがあります:

# --soft: コミットのみ取り消し(変更はステージングに残る)
git reset --soft HEAD~1

# --mixed(デフォルト): コミットとステージングを取り消し
git reset HEAD~1

# --hard: すべてを取り消し(変更も削除)※危険
git reset --hard HEAD~1

各コマンドの使い分け

状況別の選択ガイド

状況推奨コマンド理由
直前のコミットのtypo修正git commit --amend簡単で安全
プッシュ済みのコミットを取り消しgit revert履歴が残り安全
ローカルの実験を取り消しgit reset履歴をクリーンに保てる
間違ったブランチでの作業git reset --soft + git stash作業内容を保持

危険な操作とその対策

1. プッシュ済みコミットの書き換え

# ❌ 危険:他の人が使っている履歴を書き換え
git commit --amend
git push --force  # 他の人の作業を破壊する可能性

# ✅ より安全な方法
git push --force-with-lease  # 他の変更がないか確認してからプッシュ

2. git reset --hard の危険性

# ❌ 危険:未コミットの変更が完全に失われる
git reset --hard HEAD~3

# ✅ 安全な確認方法
git status  # 未コミットの変更を確認
git stash   # 念のため保存
git reset --hard HEAD~3

3. 共有ブランチでの履歴変更

# ❌ 絶対にやってはいけない
git checkout main
git reset --hard HEAD~10
git push --force

# ✅ 正しい方法
git checkout main
git revert HEAD~10..HEAD  # revertで対応
git push

履歴を復元する方法

reflogの活用

Git reflogは、HEADの移動履歴を記録しています。

# reflogを確認
git reflog

# 出力例
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: Add feature
# ghi9012 HEAD@{2}: commit: Initial commit

# 特定の状態に戻る
git reset --hard HEAD@{1}

削除されたコミットの復元

# 削除されたコミットを探す
git fsck --lost-found

# コミットの内容を確認
git show <commit-hash>

# ブランチとして復元
git branch recovered-branch <commit-hash>

実践演習

CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$

ファイルツリー

/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log
CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$

ファイルツリー

/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log

セキュリティ:機密情報の完全削除

filter-branchの使用(非推奨)

# 特定のファイルを履歴から完全削除
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch passwords.txt" \
  --prune-empty --tag-name-filter cat -- --all

BFG Repo-Cleanerの使用(推奨)

# BFGをダウンロードして使用
java -jar bfg.jar --delete-files passwords.txt
git reflog expire --expire=now --all
git gc --prune=now --aggressive

ベストプラクティス

1. 履歴変更の原則

  • ローカルのみ: プッシュ前の履歴のみ変更
  • チーム合意: 共有履歴の変更は全員の合意を得る
  • バックアップ: 重要な変更前はブランチを作成

2. 安全な作業フロー

# 作業前の確認
git status          # 未コミットの変更を確認
git stash          # 必要なら一時保存
git branch backup  # バックアップブランチ作成

# 履歴変更作業
# ...

# 問題があれば復元
git checkout backup

3. チームでのルール

  • mainブランチでの--forceは禁止
  • 履歴変更は個人ブランチのみ
  • 共有ブランチではrevertを使用

まとめ

履歴の書き換えは強力な機能ですが、誤用すると深刻な問題を引き起こします。基本的には:

  1. プッシュ前: amend、reset、rebaseを自由に使用
  2. プッシュ後: revertで対応
  3. 共有ブランチ: 履歴変更は避ける

これらの原則を守ることで、安全かつ効果的に履歴を管理できます。

次のレッスンでは、Gitの動作をカスタマイズする「フックとカスタマイズ」について学びます。

さらに学習を続けるには

素晴らしい学習ペースです!次のレッスンに進むには、無料会員登録をお願いします。無料会員では各コース3レッスンまで学習できます。

無料で続きを学ぶ

各コース3レッスンまで学習可能

学習進捗の自動保存

コース修了証明書の発行