撤销三件套:reset / restore / revert 怎么选
三个命令都带「撤销」字眼,却作用在不同对象上。一句话:reset 动指针、restore 救文件、revert 改历史。下面按场景讲清楚该用哪一个。
最后更新:2026-10-29
三句话分清
- git reset:移动分支指针(并可选择改动暂存区 / 工作区),用来「回退提交、整理历史」。
- git restore:只恢复文件内容,不影响提交历史,用来「丢弃改动 / 把文件弄回某个状态」。
- git revert:生成一个新提交来「抵消」某次旧提交,用来安全地撤销已经推送到共享分支的历史。
下面先用一张表看全局,再按场景对号入座。
一句话对比
| 维度 | git reset | git restore | git revert |
|---|---|---|---|
| 作用对象 | 分支指针(提交历史) | 工作区 / 暂存区的文件 | 提交历史(生成反向提交) |
| 是否产生新提交 | 否,改写历史 | 否 | 是 |
| 能否撤销已推送 | 不推荐(改写共享历史) | 否(只动本地文件) | 是(推荐) |
| 常见用途 | 回退本地提交、整理历史 | 丢弃未提交改动、恢复误删文件 | 撤销已公开的提交 |
| 危险点 | --hard 会丢工作区改动 | 方向指错会覆盖文件 | 基本安全 |
该用哪一个?
- 「我刚 commit,但想重做 / 合并成一次」→ git reset(仅本地)
- 「我改乱了文件,想回到上次 commit 的状态」→ git restore
- 「我不小心把改动加进了暂存区,想拿出来」→ git restore --staged
- 「我已经 push 了,需要撤销那次提交且不让队友炸」→ git revert
# 记住一句口诀
# reset 动指针 / restore 救文件 / revert 改历史git reset:移动分支指针
reset 的三个常用模式,区别在「动不动暂存区和工作区」:
git reset --soft HEAD~1 # 只移动指针;暂存区和工作区原样保留(适合重新提交)
git reset --mixed HEAD~1 # 默认模式;指针移动 + 暂存区清空(改动回到工作区)
git reset --hard HEAD~1 # 指针移动 + 暂存区和工作区都还原(工作区改动会丢失!)注意:--hard 会丢掉工作区未提交的改动,且改写历史,只用于尚未共享的提交。后悔了?只要提交过,用 git reflog 仍能找回被移开的提交(详见急救手册)。
git restore:恢复文件
restore 专治「文件改乱了 / 删了 / 加错暂存区」,它不碰提交历史:
git restore README.md # 工作区文件恢复到最近一次提交的状态(丢弃改动)
git restore --staged app.js # 只把文件移出暂存区,改动仍留在工作区
git restore --source=HEAD~1 app.js # 把文件恢复到上一个提交时的内容与 reset 不同,restore 默认只影响文件、不会移动分支指针,语义更清晰。Git 2.23+ 推荐用它替代 git checkout 的文件恢复用法。
git revert:安全地撤销已公开历史
revert 不改变任何已有提交,而是新建一个「反向」提交来抵消目标提交的效果:
git revert <commit> # 撤销单个提交,生成一个新的反向提交
git revert HEAD~2..HEAD # 撤销一段提交(按从旧到新逐个生成反向提交)因为产生的是新提交,可以安全 push 到共享分支,队友拉取后历史依然连续。适合「线上出 bug,要紧急回滚但不想改写历史」的场景。
常见误区
- 误区:reset --hard 能「找回」已删除的提交。
真相:reset 只是移动指针,提交对象还在,用git reflog可找回;但 --hard 会丢工作区未提交改动,且对「已 push」的提交不可取。 - 误区:restore 能撤销提交。
真相:restore 只动文件、不碰历史;要撤销提交用 reset(本地)或 revert(已推送)。 - 误区:revert 会删掉原提交。
真相:原提交完整保留,revert 只是追加一个反向提交。
常见问题
撤销之后提交记录还在吗?
取决于命令。git revert 一定保留(它新增一个反向提交);git reset --hard 会改写历史,但被移开的提交对象通常仍在本地 90 天内,可用 git reflog 找回;只有 reset --hard 之后又做了垃圾回收才会真正消失,这种情况很少见。
已经 push 的提交怎么撤销最安全?
用 git revert:它生成一个新提交来抵消旧提交的效果,可以正常 push 到共享分支,不会改写队友已经拉取的历史。绝对不要先 reset --hard 再 force push 去「抹掉」已共享的提交。
git restore 和 git checkout 有什么区别?
两者都能恢复文件,但 restore 语义更清晰:它只作用于文件,不会移动分支指针,也避免了 checkout 在「分支名」和「文件名」重名时混淆的情况。新版 Git 推荐用 restore 做文件恢复、用 switch 做分支切换。