Skip to content

⏪ 第六章:撤销与回退 —— 后悔药指南

⚠️ 注意: 这一章涉及一些危险操作。在学习之前,请记住一个铁律:已经 push 到远程仓库的提交,不要轻易修改,否则你的队友会找你"聊天"的。

git restore—— 丢弃工作区的修改

bash
# 场景:小明修改了 index.html,但觉得改坏了,想回到上次提交的状态

# 先看看改了什么
git diff index.html
diff --git a/index.html b/index.html
--- a/index.html
+++ b/index.html
@@ -4,5 +4,5 @@
   <title>我的第一个网站</title>
 </head>
 <body>
-  <h1>Hello, Git!</h1>
+  <h1>这个标题被我改坏了</h1>
 </body>

# 丢弃这个文件的修改
git restore index.html

# 验证:修改已经没了
git diff index.html
(空输出,说明没有差异)

📝 备注: git restore是 Git 2.23+ 新增的命令,比旧的git checkout -- <file>更直观。这个操作不可撤销,修改的内容会彻底消失(正常情况下无法找回,但专业数据恢复工具可能有办法)。三思而后行!

git restore --staged—— 从暂存区撤回

bash
# 场景:小明把 style.css 添加到了暂存区,但突然想撤回
git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   style.css

# 从暂存区撤回(文件修改保留,只是取消暂存)
git restore --staged style.css

git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   style.css

简单吧?git restore 丢弃工作区修改,git restore --staged 只取消暂存但保留修改。记住这个区别就不会搞混了。

git reset—— 回退提交(三种模式)

git reset 是一个非常强大的命令,但也有三种不同的"力度",就像橡皮擦有三种硬度:

Soft Reset —— 只回退提交,保留暂存区和工作区

bash
# 回退一个提交,但修改保留在暂存区
git reset --soft HEAD~1

# 适用场景:提交信息写错了,想重新写
git reset --soft HEAD~1
git commit -m "fix: 正确的提交信息"

Mixed Reset(默认)—— 回退提交和暂存区,保留工作区

bash
# 回退一个提交,暂存区也清空,但工作区的修改还在
git reset HEAD~1

# 等同于
git reset --mixed HEAD~1

# 适用场景:想重新组织哪些文件应该放在一个提交里

Hard Reset —— 全部回退,修改消失!

bash
# ⚠️ 危险操作!所有未提交的修改都会消失!
git reset --hard HEAD~1
HEAD is now at a1b2c3d feat: 创建首页,Hello Git!

⚠️ 注意: ⚠️--hard是核弹级别的操作!它会彻底丢弃所有未提交的修改,无法通过git restore恢复。在使用前,请确保你真的不需要那些修改了。如果只是想"让分支指向另一个提交",考虑用git revert更安全。

模式提交历史暂存区工作区
--soft回退 ✗保留 ✓保留 ✓
--mixed回退 ✗回退 ✗保留 ✓
--hard回退 ✗回退 ✗回退 ✗

git revert—— 安全地"撤销"提交

如果 git reset 是时光倒流(修改历史),那 git revert 就是写一封"撤回邮件"——它不修改历史,而是创建一个新的提交来"抵消"之前的提交。

bash
# 撤销最近一次提交
git revert HEAD
[main c3d4e5f] Revert "feat: 添加欢迎语"
 1 file changed, 1 insertion(+), 1 deletion(-)

# 查看历史,注意 revert 提交还在
git log --oneline
c3d4e5f (HEAD -> main) Revert "feat: 添加欢迎语"
f4e5d6c feat: 添加欢迎语
b2c3d4e feat: 添加基础样式
a1b2c3d feat: 创建首页,Hello Git!

💡 提示: 对于已经 push 到远程的提交,永远用git revert而不是git reset。因为 revert 不会改变历史,你的队友不会受到影响。

git reflog—— 最后的救命稻草

如果说 Git 是时光机,那 reflog 就是时光机的操作日志——它记录了 HEAD 指针的每一次移动。

bash
# 场景:小明手抖执行了 git reset --hard,把修改全删了!

# 别慌!先看 reflog
git reflog
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
f4e5d6c HEAD@{1}: commit: feat: 添加欢迎语
b2c3d4e HEAD@{2}: commit: feat: 添加基础样式
a1b2c3d HEAD@{3}: commit (initial): feat: 创建首页,Hello Git!

# 找到你想要恢复的那个提交
# f4e5d6c 就是"添加欢迎语"那次提交

# 恢复到那个状态!
git reset --hard f4e5d6c
HEAD is now at f4e5d6c feat: 添加欢迎语

# 修改回来了!

📝 备注: reflog默认保留 90 天的记录。只要在这 90 天内,几乎任何"手抖"操作都可以恢复。这就是 Git 的安全网。