Git 的回退功能非常強大,但因為有多個命令,初學者很容易混淆。我們來系統地梳理一下最核心的幾個“回退”指令:git reset
、git revert
和 git restore
。
我會按照使用場景和安全級別來為你講解。
核心區別:reset
vs revert
這是最重要的區別,理解了它就理解了 Git 回退的精髓:
-
git reset
(重置/回滾): 會修改提交歷史。它像一臺時間機器,直接把你的分支帶回到過去某個點,后面的歷史記錄就“消失”了。- 適用場景:只在你自己的本地分支上使用。因為會修改歷史,絕對不要在已經推送到遠程的公共分支(如
main
,develop
)上使用! - 危險性:較高,尤其是
--hard
模式。
- 適用場景:只在你自己的本地分支上使用。因為會修改歷史,絕對不要在已經推送到遠程的公共分支(如
-
git revert
(撤銷/反轉): 不會修改歷史,而是創建一個新的提交來抵消掉某個舊的提交。它像是在賬本上寫一筆“負數”來沖銷之前的錯誤記錄,而不是撕掉那一頁。- 適用場景:安全,適用于任何分支,尤其是已經推送到遠程的公共分支。這是團隊協作中推薦的回退方式。
- 危險性:低。
1. git reset
:強大的本地時間機器
git reset
主要用來回退未推送的本地提交。它有三種模式,決定了它對你的工作區和暫存區的影響。
假設你的提交歷史是 A -> B -> C
,當前在 C
(HEAD
指向 C
)。現在你想回退到 B
。
git reset <commit-B-hash>
# 或者更常用的,回退到上一個版本
git reset HEAD~1
三種模式:
-
--soft
(溫柔模式)- 命令:
git reset --soft HEAD~1
- 效果:
- 提交歷史: 回退到
B
。C
的提交被撤銷。 - 暫存區 (Staging Area): 保留
C
提交時的所有更改,這些更改會處于“已暫存”狀態。 - 工作區 (Working Directory): 保留
C
提交時的所有代碼,文件內容不變。
- 提交歷史: 回退到
- 一句話總結:撤銷了提交,但保留了所有代碼更改并放在暫存區,你可以馬上重新提交。
- 應用場景:“我剛才的提交信息寫錯了,或者漏了幾個文件,想把它們合并成一個新提交。”
- 命令:
-
--mixed
(默認模式)- 命令:
git reset HEAD~1
(不加參數時默認就是--mixed
) - 效果:
- 提交歷史: 回退到
B
。 - 暫存區: 清空。
C
提交時的更改被移出暫存區。 - 工作區: 保留
C
提交時的所有代碼,文件內容不變。
- 提交歷史: 回退到
- 一句話總結:撤銷了提交,也撤銷了
git add
,但代碼還在。 - 應用場景:“我剛才的提交不僅有問題,我還想重新檢查一下到底哪些文件需要提交。”
- 命令:
-
--hard
(硬核/危險模式)- 命令:
git reset --hard HEAD~1
- 效果:
- 提交歷史: 回退到
B
。 - 暫存區: 清空。
- 工作區: 代碼被丟棄。你的文件會完全恢復到
B
提交時的狀態。
- 提交歷史: 回退到
- 一句話總結:徹底抹除
C
提交的所有痕跡,包括代碼更改。 - ?? 警告:這是一個破壞性操作!任何未提交的本地修改、以及
--hard
模式回退掉的提交內容,如果沒有備份,就很難找回了。 - 應用場景:“我最近的幾次提交完全是垃圾,我想徹底扔掉它們,從頭再來。”
- 命令:
2. git revert
:安全的企業級“撤銷”
當你發現一個已經推送到 main
分支的提交 C
引入了一個 Bug,你不能用 git reset
,因為這會搞亂團隊其他成員的歷史。這時就該用 git revert
。
如何使用:
假設你要撤銷提交 C
(commit-C-hash
) 的更改。
git revert <commit-C-hash>
-
效果:
- Git 會創建一個新的提交
D
。 D
提交的內容,剛好是C
提交內容的反向操作。比如C
中添加了一行代碼,D
就會刪除那一行。- 你的提交歷史會變成
A -> B -> C -> D
。 - Git 會自動打開編輯器讓你填寫這次撤銷操作的提交信息。
- Git 會創建一個新的提交
-
一句話總結:用一次新的、正確的提交,來“糾正”一次舊的、錯誤的提交。
-
應用場景:“線上代碼出 Bug 了,需要立刻回滾某個已經發布的提交,同時保持歷史記錄的清晰和團隊協作的穩定。”
3. git restore
& git checkout --
:撤銷工作區的修改
這兩個命令主要用于處理尚未提交的更改。
git restore
是較新的命令,語法更清晰,推薦使用。
場景一:撤銷對工作區文件的修改(還沒 git add
)
你不小心改亂了一個文件,想把它恢復到上次提交時的樣子。
# 新語法 (推薦)
git restore <file_name># 舊語法
git checkout -- <file_name>
效果:file_name
在你工作區的修改會被丟棄,恢復成和暫存區/上次提交一樣的版本。
場景二:把文件從暫存區撤銷(已經 git add
,但還沒 git commit
)
你用 git add
把一個不想提交的文件加到了暫存區。
# 新語法 (推薦)
git restore --staged <file_name># 舊語法
git reset HEAD <file_name>
效果:文件會從暫存區移除,但工作區的修改內容仍然保留。
如何選擇:一個簡單的決策流程
-
這次回退需要影響公共歷史嗎?(即,代碼已
push
到main
/develop
)- 是 ->
git revert
(安全第一) - 否 -> 繼續看第 2 步。
- 是 ->
-
你想撤銷的是已經
commit
的提交嗎?- 是 ->
git reset
- 想保留代碼并重新提交? ->
reset --soft
- 想保留代碼但重新暫存? ->
reset --mixed
- 想徹底丟掉代碼? ->
reset --hard
??
- 想保留代碼并重新提交? ->
- 否 (只是工作區或暫存區的修改) -> 繼續看第 3 步。
- 是 ->
-
你想撤銷的是
git add
操作嗎?- 是 ->
git restore --staged <file>
- 否 (只是想丟棄文件的本地修改) ->
git restore <file>
- 是 ->
記住這個流程,你就能在各種場景下選擇最合適、最安全的回退指令了。