Git 提交后发现写错了怎么撤销?已 commit 未推送的 3 种方法

编程狮(w3cschool.cn) 2026-08-12 15:18:45 浏览数 (23)
反馈

Git 撤销提交,就是让你把已经 commit 但还没推送到远程的改动安全地收回来。你刚敲完 git commit,突然发现漏了文件,或者提交说明写错了,心里一紧:这下历史是不是乱了?其实只要这个提交还没 push 到远程,就有好几种干净的补救办法。最常用的是 git reset 回到上一个版本,已经推送过的则用 git revert 生成反向提交。今天这篇文章,编程狮就把三种处理方法一次讲清,并说清什么情况用哪一个,让你以后遇到提交事故不再手忙脚乱。很多新手一看到 commit 错了就慌,其实 Git 的设计里,「提交」从来不是不可逆的终点,而只是一次可移动的指针。理解了这个比喻,下面所有撤销手段都会变得很好懂。

一、先分清:提交到底推没推送到远程

在动手 Git 撤销提交之前,第一件事是确认这个提交有没有被 push 到远程仓库。这一步决定了你能用激进的方法,还是只能用安全的方法。做 Git 撤销提交最怕不分情况乱用 reset,先把情况看清,后面才不会把团队历史搞乱。

判断方法很简单,看本地和远程的差距:

# 查看本地比远程多出的提交
git status
git log origin/main..HEAD --oneline

上面这段 git log origin/main..HEAD 会列出「远程没有、只有你本地有」的提交。如果这里列出了你刚提交的那个,说明它还没推送,可以放心用 reset;如果已经 push 了,就得用 revert。如果 origin/main 这个名字不对,换成你实际跟踪的分支,比如 origin/master

💡 小提示:如果你对 Git 的工作区、暂存区、版本库这三层关系还模糊,先过一遍 Git 教程 把基础模型补上,再看撤销会轻松很多。

1.1 提交的本质

每次 git commit 都会生成一个快照,并用一个长长的哈希值标记。git 撤销 commit 并不是把快照删掉,而是移动一个叫 HEAD 的指针,让它指向别的地方。理解了这一点,下面三种方法就不会再让你害怕,也知道改写的是提交历史而非文件本身,回滚是有迹可循的。

1.2 用 reflog 给自己留条后路

在你试各种撤销之前,先记住一个保命命令:git reflog。它会记录 HEAD 每一次移动,哪怕你 reset --hard 把提交弄丢,也能在这里找到那个哈希值再跳回去。所以大胆试,只要没 push,基本都能救回来。

二、方法一:git reset,本地未推送时的首选

git reset 有三种模式,差别只在「会不会动你的文件」:

git reset --soft HEAD~1   # 只移动指针,改动留在暂存区
git reset --mixed HEAD~1  # 移动指针,改动退回工作区(默认)
git reset --hard HEAD~1   # 移动指针,并且丢弃所有改动(危险)

上面这三行,HEAD~1 表示「当前提交的前一个」。--soft 最温和,你的代码改动原封不动,只是提交被撤掉,可以重新写说明再提交;--mixed 是默认行为,改动还在但退出了暂存区;--hard 最狠,改动直接消失。

做 Git 撤销提交时,绝大多数情况用 --mixed--soft 就够了,把 --hard 留到最后关头。关于命令的细节和参数,可以翻 Git 速查手册 随时查,它把 reset、revert、checkout 的差别列成了对照表。另外,reset 之后如果想反悔,只要还没做别的新提交,再 reset 一次就能回去,HEAD 的移动本身就是一条可逆的记录,这也是 reflog 能救命的原因。

⚠️ 注意:一旦提交被推送到远程、并且别人可能已经基于它工作,就绝不要用 git reset --hard 去改写公共历史,那会把别人的工作搞乱。这种场景请直接看第三节的 revert。

三、方法二:git revert,已推送也安全的做法

如果提交已经 push 到远程,正确的 Git 撤销提交方式是 revert:它会生成一个「反向提交」,把那次改动的内容抵消掉,但历史记录依然完整保留。Git 撤销提交在团队协作里的正确姿势,就是 revert。如果想先看 revert 会改成什么样、暂不提交,可以加 -n(或 --no-commit)参数,它会把改动放进工作区让你检查,确认无误再手动提交。多这一步,在改重要历史时更稳。

# 撤销某一个提交(会打开编辑器写新的提交说明)
git revert <commit-hash>
# 连续撤销最近两个提交
git revert HEAD~2..HEAD

上面这段里,<commit-hash> 换成你要撤销的那次提交的哈希值。revert 不改变已有的历史,只是往前加了一笔,所以对公共分支、对协作团队都是安全的。它不会改变任何人的本地历史,只是新增一个提交,因此永远不会破坏别人已有的工作。

想看 reset、revert、checkout 三种撤销方式更直观的横向对比,这篇 Git 怎么回退到上一个版本? 可以作为补充阅读,它把每种场景该用哪条命令讲得很清楚。

四、方法三:git commit --amend,只改最近那一次

如果你只是提交说明写错了,或者漏了文件、想合并进同一次提交,最轻量的 Git 撤销提交方式是 amend:

# 先补上漏掉的文件
git add 漏掉的文件.py
# 把改动并进最近一次提交,并重新编辑说明
git commit --amend

上面这段做的是把当前暂存区的内容,和最近那次提交合并成一次新的提交,提交哈希会变,但对外看起来就像「那次提交本来就是对的」。它本质上也是改写历史,所以只适用于还没推送的提交。如果你只想改提交说明、不动文件,用 git commit --amend -m "新的说明" 可以一步到位,不必进编辑器。但要注意,只要加了 --amend,哪怕只改说明,提交哈希也会变,所以依然只限未推送的提交。

想搞懂 HEAD 指针和对象模型这些更底层的东西,Git Magic 教程 讲得更透,适合你想从原理层面理解 Git 的时候翻阅。

总结

Git 撤销提交并不恐怖,核心是先看提交有没有推送。没推送、想回退,用 git reset(优先 --soft/--mixed,慎用 --hard);已推送、要安全,用 git revert 生成反向提交;只改最近一次说明或补文件,用 git commit --amend。

要点带走:

  • reset 会移动指针,--hard 会丢改动,公共分支禁用;
  • revert 不删历史,适合已推送的提交;
  • amend 只改最近一次,适合提交说明写错;
  • 动手前先 git status 确认提交还在本地。

下一步,把分支、暂存区、工作区这三者的关系理清楚,你对 Git 的掌控感会强很多。

延伸学习

想把 Git 用熟,可以按这个顺序来:

  1. 先过一遍 Gitcourse 课程,把提交、分支、撤销这些基础操作练熟;
  2. 想换个角度理解分布式版本控制,Txygit 课程 是另一条学习路径。

常见问题

Q:git reset --hard 之后,误删的提交还能找回来吗?
A:大概率可以。Git 的对象短时间内不会被立刻清理,用 git reflog 找到被移动前的那个哈希值,再 git reset --hard <hash> 就能回到误删前的状态。所以养成提交后先看 reflog 的习惯很有用。

Q:revert 之后还能再 revert 回来吗?
A:可以。revert 生成的也是一个普通提交,如果反悔了,把那次 revert 提交再 revert 一次即可,历史始终是向前追加,不会破坏协作。

Q:amend 改过的提交已经 push 了,怎么办?
A:已经推送的提交不要再用 amend 改写,否则远程和本地历史会对不上。正确做法是当做一次新改动重新提交,或者用 revert 抵消,保持历史线性。

0 人点赞