在實務專案中,常常會遇到「想把剛剛的動作撤回」的狀況。
Git 在 2.23 版之後,將這類需求拆成兩種命令:
git restore
:專注於「檔案狀態」的還原git reset
:專注於「提交歷史」的回退兩者功能有部分重疊,但設計理念不同,今天我們就來完整拆解。
要搞懂這兩顆藥的差別,先複習 Git 的三大區域:
git reset
與 git restore
的差異,核心就在於:👉 它們作用的「範圍」不同。
git restore
:溫和後悔藥 —— 專治檔案狀態用於「檔案層級」的操作,處理檔案的修改或暫存。
還原 工作目錄的修改:
git restore <檔案or目錄>
# 還原檔案
git restore index.js
# 還原整個目錄
git restore src/
效果:
情況 1:暫存區沒有修改加入
工作目錄的修改被還原後,檔案回到 最後一次 commit 的狀態
情況 2:暫存區已有修改加入
工作目錄的修改被還原後,檔案回到 暫存區的狀態(保留已暫存的修改)
🔑 記法:
restore
還原基準取決於檔案是否暫存
- 沒暫存 → 回 commit
- 已暫存 → 回暫存區
退回 暫存區的修改
git restore --staged index.js
效果:
👉 可以把 git restore
理解為:只是幫你復原「檔案狀態」,不會亂動 commit 歷史。
git reset
:強效後悔藥 —— 回退提交歷史操作的對象是 HEAD 指標,改變「目前所在的 commit」,並決定是否保留檔案修改。
git reset
會 移動 HEAD 到舊的 commit
簡單理解:HEAD = Git 裡的「現在位置指標」,操作 reset 就是把指標拉回去。
git reset
的三種模式:退回 commit 內容去哪?模式 | 被退回 commit 內容 | 暫存區 | 工作目錄 |
---|---|---|---|
--soft |
變成「已暫存的修改」 | 保留+加入退回 commit 的內容 | 保留 |
--mixed (預設) |
變成「未暫存的修改」 | 清空 | 保留+加入退回 commit 的內容 |
--hard |
直接丟掉 | 清空 | 清空 |
使用方法:
# HEAD退回 上一個 commit,保留修改與暫存
git reset --soft HEAD~
# HEAD退回 上上一個 commit,保留修改,但清除暫存
git reset --mixed HEAD~2
# HEAD退回 上一個 commit,所有修改與暫存都清掉
git reset --hard HEAD~1
這是非常危險的操作,因為一旦刪掉,版本歷史就被改寫了。
💡 小技巧:Git 會把危險操作前的狀態記錄在 .git/ORIG_HEAD
。
萬一誤刪,可以這樣救回來:
git reset ORIG_HEAD --hard
🔑 記法:
--soft
→ commit 退回到暫存區(等你改訊息、再 commit)--mixed
→ commit 退回到工作目錄(清空暫存區、等你重新 add)--hard
→ commit 直接丟掉(暫存區和工作目錄全清空)
⚠️ 特別提醒:reset --hard
會清掉所有修改,請務必小心使用!
在 Git 2.23 之前,很多人習慣用 git reset
來撤銷暫存或丟掉修改
但這樣常常導致誤解甚至誤操作。
所以官方新增了 git restore
和 git switch
,讓指令語意更清晰:
reset
:操作 commit 歷史restore
:管理檔案狀態switch
:管理分支 (先知道存在,暫時不展開)這樣分工之後,使用者能更直覺理解自己在做什麼。
指令 | 作用範圍 | 危險程度 | 適用場景 | 建議 |
---|---|---|---|---|
git restore |
檔案層級 | 🟢 低(安全) | 檔案修改錯誤、誤加暫存 | 小動作用 restore |
git reset |
commit 歷史 | 🟡🔴 中~高(需謹慎) | commit 做錯、想回到舊版本 | 大動作用 reset |
👉 藥這樣選:
- 如果只是想「退掉檔案變更」或「取消暫存」 → 用
git restore
- 如果是「回到某個 commit」或「重做提交」 → 用
git reset
git restore
= 溫和藥,專治檔案操作,不動歷史,適合日常修正。git reset
= 強效藥,能直接抹掉 commit,危險但強大。
reset --hard
真的危險!很多新手第一次接觸的時候,會覺得它超好用。
但要注意,它會直接把檔案清空回舊狀態,沒有任何回收桶!
👉 如果真的要用,建議先把 commit_id 記下來,避免不小心把重要工作全抹掉。
git add
,用 git restore <檔案>
丟掉修改。git add
,再用 git restore --staged
把它從暫存區移出。git reset --soft HEAD~1
,觀察修改與暫存的狀態變化。今天我們學會了兩顆 Git 的「後悔藥」:
git restore
→ 檔案級的後悔藥,還原檔案狀態(取消暫存、丟掉修改)git reset
→ 歷史級的後悔藥,回退提交歷史(保留或丟棄修改)git reset --hard
,用錯真的會哭理解它們的差異,就能根據情境選對藥,既能保命,也能避免誤傷。