Git 撤销操作 — reset / revert / restore 救命指南
"我刚才提交错了!""这段代码改坏了想退回去!""把密钥提交进去了怎么办!"——这是 Git 最常救场的场景。撤销操作根据"改动的阶段"和"是否已 push"有不同的方法。这一章把所有撤销套路整理成一张清晰的地图,记牢它能在关键时刻救命。
先搞清楚:你在哪个阶段?
撤销操作的关键是判断改动现在在哪个阶段,不同阶段用不同命令:
- 还在工作区(没 add):用
git restore。 - 进了暂存区(add 了没 commit):用
git restore --staged。 - 已经 commit 但没 push:用
git reset或commit --amend。 - 已经 push:用
git revert(绝不能 reset!)。
1. 撤销工作区与暂存区的改动
这两个阶段用 git restore(Git 2.23 引入,替代了 checkout 的混乱用法):
# 阶段 1:还没 add — 撤销工作区的修改
# 场景:改了 file.txt,发现改错了,想恢复成最近一次提交的样子
git restore file.txt # 新命令(推荐)
git checkout -- file.txt # 老命令(等价)
# 一次性恢复整个工作区(危险!所有未提交改动都没了)
git restore .
# 恢复成某个历史版本(不是最近一次提交)
git restore --source=HEAD~3 file.txt
# ---
# 阶段 2:已经 add 还没 commit — 从暂存区撤回
# 场景:误把 .env 加进暂存区了,想拿出来
git restore --staged file.txt # 新命令(推荐)
git reset HEAD file.txt # 老命令(等价)
# 撤回所有暂存的文件
git restore --staged .
# 注意:这只会让文件"退出暂存区",工作区的内容不变
# 想彻底丢弃改动,再 git restore file.txt2. git reset — 撤销提交(还没 push 时)
reset 是"移动分支指针"的命令。把它往后移,就等于"撤销"了那些提交。它有三种模式,区别在于被撤销的改动留在哪里:
# 阶段 3:已经 commit 但还没 push — 用 reset 撤销提交
# reset 有三种模式,区别在于"改动留在哪里"
# soft:撤销提交,但改动完整留在暂存区(可重新 commit)
git reset --soft HEAD~1
# 适合:刚 commit 完发现 message 写错了,想重新写
# mixed(默认):撤销提交,改动留在工作区(变未暂存)
git reset HEAD~1 # 不写模式就是 mixed
# 适合:想重新挑选哪些改动进这次提交
# hard:撤销提交,改动也丢弃(彻底!)
git reset --hard HEAD~1
# 适合:这次提交完全不要了,代码也回退
# 警告:工作区未提交的改动也会丢!
# ---
# reset 到指定提交(不是只回退一个)
git reset --hard a1b2c3d # 回到 a1b2c3d 那个状态
# reset 后想"反悔"?用 reflog 找回!
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: feat: 添加登录 ← 这个被 reset 掉了
git reset --hard e4f5g6h # 又回来了!一张速查表:
--soft:撤销 commit,改动留在暂存区(可直接重新 commit)。--mixed(默认):撤销 commit,改动留在工作区(变未暂存)。--hard:撤销 commit,改动彻底丢弃(不可恢复,除非 reflog)。
3. git revert — 撤销已 push 的提交
这是最容易被新手搞错的地方:已经 push 到共享分支的提交,绝对不能用 reset 撤销——因为那会改写历史,别人 pull 时会爆炸。正确做法是用 git revert,它会生成一个反向提交(把目标提交的改动反过来做一遍),历史是"增加"的,不改写:
# 阶段 4:已经 push 到共享分支 — 用 revert(不要 reset!)
# 场景:已经 push 的提交发现有问题,要撤销
# 但别人可能已经 pull 走了,不能改写历史
# revert 会生成一个"反向提交",效果是抵消掉指定提交
git revert HEAD # 撤销最近一次提交
git revert a1b2c3d # 撤销指定的某次提交
# 工作流:
# 1. Git 自动算出"反向改动"
# 2. 打开编辑器让你写 revert message(默认就行)
# 3. 生成一个新的"撤销提交"
# 4. git push 推上去
# 历史效果:
# 原来: A - B - C (C 是有问题的)
# revert C 后:A - B - C - C' (C' 是反向提交,内容等于撤销 C)
# 历史是"增加"的,没有改写,别人 pull 不冲突
# 撤销一段连续提交(范围)
git revert HEAD~3..HEAD
# 撤销一个合并提交(高级,需要 -m 指定保留哪个父)
git revert -m 1 a1b2c3d黄金法则(最重要)
已经 push 到共享分支的提交,绝不 reset --hard / rebase / amend。
原因:这些操作会改写提交哈希。同事已经基于旧哈希在工作,你改写后他们 pull 时,Git 会认为这是两份不同的历史,产生无法自动解决的冲突——轻则大家浪费时间,重则代码丢失。
- 公共分支(main/develop/共享 feature):只能用
revert。 - 私人分支(只有你用):随便 reset/rebase/amend,push 时用
--force-with-lease。
4. git commit --amend — 修改最近一次提交
这是日常最高频的"小撤销":刚 commit 完发现 message 写错、漏了文件、多加了文件。amend 把当前暂存区的改动并入上一个提交(并可改 message):
# 修改最近一次提交(还没 push 时最常用)
# 场景 A:刚 commit 完,发现 message 写错了
git commit --amend -m "feat: 正确的提交信息"
# 场景 B:刚 commit 完,发现漏了一个文件
git add 漏的文件.txt
git commit --amend --no-edit # --no-edit 保持原 message
# 场景 C:想改最近一次提交的作者信息
git commit --amend --author="新名字 <new@example.com>"
# 注意:amend 会改写提交哈希!
# - 还没 push:随便 amend,安全
# - 已经 push 到私人分支:可以,但要 force-with-lease 推
# - 已经 push 到共享分支:绝对不要 amend(用 revert 代替)
# ---
# 修改更早的提交(用交互式 rebase,见 rebase 篇)
git rebase -i HEAD~3
# 把想改的那行改成 edit,保存,Git 会暂停在那个提交5. git clean — 清理未追踪文件
reset 只能处理"已追踪文件的改动",对"全新的、没 add 过的文件"无能为力。这时用 git clean:
# git clean:删除"未追踪"的文件(reset 管不到的)
# 场景:工作区有一堆临时文件、构建产物,Git 没追踪,想清掉
# 预览:会删哪些(干跑一遍,不真删)
git clean -n
# 真删未追踪文件
git clean -f
# 连目录一起删(比如 dist/ 这种)
git clean -fd
# 连 .gitignore 忽略的文件也删(彻底清理)
git clean -fdx
# 慎用!这会删掉 node_modules、.env 等
# reset + clean 组合拳 = 工作区完全回到某个提交
git reset --hard HEAD
git clean -fd误删了怎么办?reflog 救你
即使 reset --hard 把提交"删了",只要它曾经被 commit 过,本地 reflog 里就有记录,能找回:
git reflog看所有 HEAD 移动记录。- 找到"丢失"那个提交的哈希。
git reset --hard 那个哈希神奇恢复。
所以养成"勤 commit"的习惯——哪怕 message 写 wip,至少进了历史,reflog 兜底;只在工作区改、从没 commit,那才是真没了。
一张图记住所有撤销命令
- 改了工作区 →
git restore 文件 - add 错了 →
git restore --staged 文件 - commit 错了(没 push)→
git reset HEAD~1或git commit --amend - push 错了 →
git revert HEAD - 彻底清空工作区 →
git reset --hard HEAD+git clean -fd - 找回来的希望 →
git reflog
Git 是那种"用一年才知道自己之前用错了"的工具,但每个命令背后都是干净的逻辑。坚持写有意义的 commit message、保持分支整洁、养成 PR review 习惯,你会成为团队里最受欢迎的协作伙伴。
← 上一篇 Git 历史与差异
← 返回 Git 教程目录