git revert - 還原 Commit
git revert 建立一個新的 commit 來「反轉」之前的 commit,是安全地撤銷變更的方式。
Revert vs Reset
最大的差別是:
- Reset:直接刪除 commit,改變歷史
- Revert:建立新的 commit 來撤銷,保留歷史
Reset 前: A --- B --- C
Reset 後: A --- B
Revert 前: A --- B --- C
Revert 後: A --- B --- C --- C'(反轉 C)
Revert 是安全的,因為它不會改變歷史,適合已經推送的 commit。
基本用法
還原最後一個 Commit
git revert HEAD
Git 會開啟編輯器讓你編輯 revert commit 的訊息,預設訊息是:
Revert "Original commit message"
This reverts commit a1b2c3d4e5f...
還原特定 Commit
git revert a1b2c3d
不開啟編輯器
git revert HEAD --no-edit
只做變更不 Commit
git revert HEAD --no-commit
# 或
git revert HEAD -n
這會把 revert 的變更放到暫存區,但不自動 commit,讓你可以做額外修改或合併多個 revert。
還原多個 Commit
一次還原一個
git revert HEAD
git revert HEAD~1
git revert HEAD~2
每個 revert 都會產生一個新的 commit。
還原一個範圍
# 還原從 HEAD~3 到 HEAD 的 commit(不含 HEAD~3)
git revert HEAD~3..HEAD
# 還原並合併成一個 commit
git revert HEAD~3..HEAD --no-commit
git commit -m "Revert last 3 commits"
還原 Merge Commit
Merge commit 有兩個父 commit,revert 時需要指定要保留哪一邊:
# -m 1 保留第一個父 commit(通常是被合併到的分支)
git revert -m 1 <merge-commit>
# -m 2 保留第二個父 commit(被合併進來的分支)
git revert -m 2 <merge-commit>
假設你把 feature merge 到 main:
main: A --- B --- M(merge commit)
\ /
feature: C
要撤銷這個 merge,保留 main 的 B:
git revert -m 1 M
還原 merge commit 後,如果之後想重新 merge 那個分支,需要先 revert 這個 revert。否則 Git 會認為那些變更已經被處理過了。
處理衝突
Revert 也可能遇到衝突:
git revert a1b2c3d
# CONFLICT: 衝突發生
# 1. 解決衝突
code conflicted-file.js
# 2. 標記已解決
git add conflicted-file.js
# 3. 繼續 revert
git revert --continue
放棄 revert:
git revert --abort
實際範例
情境一:撤銷最近的錯誤 Commit
# 有問題的 commit 已經推送
git revert HEAD
git push
情境二:撤銷中間的某個 Commit
# 假設 commit 歷史是 A-B-C-D,想撤銷 B
git log --oneline
# d4e5f6g D - Latest
# c3d4e5f C
# b2c3d4e B - 有問題的 commit
# a1b2c3d A
git revert b2c3d4e
情境三:撤銷整個功能(多個 Commit)
# 假設最後 5 個 commit 都是某個功能
git revert HEAD~5..HEAD --no-commit
git commit -m "Revert: Remove feature X"
情境四:撤銷已合併的 Pull Request
# 找到 merge commit
git log --merges
# 還原 merge(保留 main 分支的狀態)
git revert -m 1 <merge-commit-hash>
git push
情境五:重新加回被 Revert 的變更
# 假設之前 revert 了 commit A
# 現在想把 A 的變更加回來
# 方法一:revert 那個 revert commit
git revert <revert-commit-hash>
# 方法二:cherry-pick 原本的 commit
git cherry-pick <original-commit-hash>
Revert vs 其他撤銷方式
什麼時候用 Revert
- Commit 已經推送到遠端
- 想保留完整的歷史紀錄
- 團隊協作,不想影響其他人
什麼時候用 Reset
- Commit 還沒推送
- 只在本地開發
- 想完全清除某些 commit
什麼時候用 Checkout
- 只想查看之前的狀態
- 不想修改任何東西
查看 Revert 的效果
在 revert 前,可以先看看會有什麼變化:
# 查看某個 commit 的內容
git show a1b2c3d
# 模擬 revert(不實際執行)
git revert a1b2c3d --no-commit
git diff --staged
git revert --abort
小技巧
批次 Revert 合併成一個 Commit
git revert HEAD~3..HEAD --no-commit
git commit -m "Revert: Remove problematic changes"
使用 dry-run 測試
Git revert 沒有 dry-run 選項,但你可以:
# 先在新分支測試
git checkout -b test-revert
git revert a1b2c3d
# 確認沒問題後,在原分支執行
git checkout main
git revert a1b2c3d
# 刪除測試分支
git branch -D test-revert