なぜ履歴を変更するのか?
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を使用
まとめ
履歴の書き換えは強力な機能ですが、誤用すると深刻な問題を引き起こします。基本的には:
- プッシュ前: amend、reset、rebaseを自由に使用
- プッシュ後: revertで対応
- 共有ブランチ: 履歴変更は避ける
これらの原則を守ることで、安全かつ効果的に履歴を管理できます。
次のレッスンでは、Gitの動作をカスタマイズする「フックとカスタマイズ」について学びます。