git reset - 重置 Commit
git reset 用來移動 HEAD 和分支指標,可以用來取消 commit、取消暫存,或回到之前的狀態。
Reset 的三種模式
Git reset 有三種模式,影響的範圍不同:
--soft 只移動 HEAD,保留暫存區和工作目錄
--mixed 移動 HEAD,重置暫存區,保留工作目錄(預設)
--hard 移動 HEAD,重置暫存區和工作目錄
git reset --soft
git reset --soft HEAD~1
- 取消最後一個 commit
- 變更保留在暫存區
- 工作目錄不變
適用情境:想重新編輯 commit 訊息或合併 commit。
# 取消 commit 但保留變更在暫存區
git reset --soft HEAD~1
# 重新 commit
git commit -m "New message"
git reset --mixed(預設)
git reset HEAD~1
# 等同於
git reset --mixed HEAD~1
- 取消最後一個 commit
- 變更移出暫存區,回到工作目錄
- 工作目錄不變
適用情境:想重新選擇要 commit 的檔案。
# 取消 commit,變更回到工作目錄
git reset HEAD~1
# 只加入部分檔案
git add specific-file.js
git commit -m "Commit only specific files"
git reset --hard
git reset --hard HEAD~1
- 取消最後一個 commit
- 重置暫存區
- 重置工作目錄(變更會遺失)
小心使用
--hard,未 commit 的變更會永久遺失!適用情境:想完全回到之前的狀態,不要任何變更。
Reset 的目標
回到前幾個 Commit
# 回到上一個 commit
git reset HEAD~1
# 回到前三個 commit
git reset HEAD~3
# 回到特定 commit
git reset a1b2c3d
使用 Commit Hash
git reset --hard a1b2c3d4e5f
使用分支名稱
git reset --hard origin/main
常見用法
取消暫存
# 取消所有暫存
git reset
# 取消特定檔案的暫存
git reset HEAD index.html
# Git 2.23+ 建議使用
git restore --staged index.html
修改最後一個 Commit
# 方法一:reset 後重新 commit
git reset --soft HEAD~1
# 修改後重新 commit
git commit -m "New message"
# 方法二:使用 amend(更簡單)
git commit --amend -m "New message"
合併多個 Commit
# 假設要合併最後三個 commit
git reset --soft HEAD~3
git commit -m "Combined commit message"
完全回到遠端的狀態
git fetch origin
git reset --hard origin/main
這會讓本地的 main 和遠端的 origin/main 完全一樣。
取消所有本地變更
# 取消所有變更,回到最後一次 commit
git reset --hard HEAD
# 或
git checkout -- .
Reset vs 其他指令
Reset vs Revert
| Reset | Revert | |
|---|---|---|
| 修改歷史 | 是 | 否 |
| 產生新 commit | 否 | 是 |
| 適合已推送的 commit | 不適合 | 適合 |
# Reset:移除 commit(會改變歷史)
git reset --hard HEAD~1
# Revert:產生反向 commit(不改變歷史)
git revert HEAD
Reset vs Checkout
# Reset:移動分支指標
git reset HEAD~1
# Checkout:移動 HEAD,不動分支
git checkout HEAD~1 # 進入 detached HEAD 狀態
復原 Reset
如果 reset 錯了,可以用 reflog 找回:
# 查看 HEAD 移動歷史
git reflog
# 找到 reset 前的位置,例如 HEAD@{1}
git reset --hard HEAD@{1}
這是為什麼即使用了 --hard,commit 通常還是可以救回來。
實際範例
情境一:Commit 了不該 commit 的檔案
# 取消最後一次 commit,但保留變更
git reset --soft HEAD~1
# 移除不該 commit 的檔案
git reset HEAD secret.env
# 重新 commit
git commit -m "Original message"
情境二:想重做最後幾個 Commit
# 回到三個 commit 之前,保留變更
git reset --mixed HEAD~3
# 重新整理並 commit
git add .
git commit -m "Refactored commit"
情境三:本地分支搞砸了
# 直接回到遠端的狀態
git fetch origin
git reset --hard origin/main
情境四:取消 Merge
# 如果還沒 commit(merge 進行中)
git merge --abort
# 如果已經 commit
git reset --hard HEAD~1
注意事項
不要 reset 已推送的 commit
Reset 會改變歷史,如果你 reset 了已經推送的 commit,然後要推送:
git push --force
這會覆蓋遠端的歷史,可能影響其他協作者。
如果 commit 已經被推送並有其他人基於它開發,請用 git revert 而不是 git reset。
未追蹤的檔案
git reset 不會影響未追蹤的檔案。要清除它們:
# 查看會被清除的檔案
git clean -n
# 清除未追蹤的檔案
git clean -f
# 清除未追蹤的檔案和目錄
git clean -fd