mrsaynothing.dev
git undo、cancel、revert——无论哪个词,改动都保住

> git undo、cancel、revert——无论哪个词,改动都保住▋

我们自己搜索看板上的每一条 keep-changes 查询——undo、cancel、revert——在一页内讲清:每种乱局对应的命令、--hard 的陷阱,以及 reflog 这张安全网。

mrsaynothing· 2026年10月11日· 2 分钟读完

✦ 修复git reset --soft HEAD~1

git 为「找回代码」准备了五个动词——undo、cancel、revert、reset、restore——但没有一个真叫 undo。某本同义词词典一定很为自己骄傲。

这就是词典的代价。上周,这个家族的头部查询——git undo last commit keep changes——带来73 次展示、排名 11.1、零点击,周环比 +100%,身后还跟着四个拼写不同的表亲。人们不是搞不懂 git。他们怕 --hard,而每篇模板化教程都用唯一一个坐实这种恐惧的 flag 来回答它。本页自上而下过一遍家族:选好动词,对好表格,然后再动历史。

全部 reset revert restore stash
人们敲的词 git 实际做的事 保住工作? 命令
"undo" 分支标签退回一个 commit;改动回到暂存区 保住——在索引里 git reset --soft HEAD~1
"cancel" 默认 reset:标签退回,改动回来但不带暂存 保住——在工作区里 git reset HEAD~1
"revert" 追加一个撤销旧 commit 的新 commit;历史从不改写 保住——以反向 diff 的形式 git revert HEAD
"unstage" 路径离开索引;文件内容原封不动 保住——工作区毫发未损 git restore --staged file.txt
"先放一边" 工作打包放上架子,随时取回 保住——在 stash 栈上 git stash push -m "wip"

唯一重要的决定

一个后悔的 commit? 从这里开始 有——别人拉过了 没有——它还属于你 git revert HEAD 历史多出一个反向 commit—— 别人手里的东西不被改写 git reset --soft HEAD~1 标签退回, 工作回到暂存区 坏改动被公开撤销 以 additive 的历史方式 重新好好提交 同样的工作,更好的信息或拆分
fig 1——推送过还是没推送:选出动词的唯一问题。两条路都保住工作;下面的 undo 生成器接收整个烂摊子。

如何撤销上一个 commit 并保留改动?

git reset --soft HEAD~1——分支标签退回一个 commit,你做的一切回到暂存区。什么都没删,什么都没离开索引;可以用更好的信息重新提交,或把工作拆开。完整走查(含已推送的情况)在 git undo last commit: keep changes, stay safe。

verify:reset 之后,git status 应该在「Changes to be committed」里显示你的文件——那就是被还给你的工作。

"git undo commit keep changes" 是另一回事吗?

不是——同一个问题,同一个答案。「undo」从来不是 git 命令;我们的看板显示两种拼法指向完全相同的问题,且都以 reset --soft 收场。人们说 undo 时,意思是挪标签,留工作——soft reset 从始至终只做这一件事。

为什么 "git revert last commit keep changes" 的答案不同?

因为 revert 是家族里唯一往历史里加东西而不是倒带的成员。git revert HEAD 创建一个新 commit,其 diff 抵消旧的——「保留改动」自动发生:坏 commit 留在记录里,工作区最终没有它。只要有别人拉过,它就是正确的工具;reset 与 revert 的分岔画在 git revert vs reset: which one saves your history?。

revert = 公开的撤销。它从不改写别人已有的东西;用一个新增的 commit 抵消变更。

"git cancel commit" 是真的命令吗?

不是——cancel 是口语,git 把口语翻译成 reset。「cancel commit but keep changes」和「cancel last commit but keep changes」——同一周里看板上的另两种拼法——都落在 git reset --soft HEAD~1 上。git 只关心你挪的标签和你传的 flag;词汇是你自己带来的。

可以删掉一个没人拉取过的 commit 吗?

可以——没推送过的 commit 仍属于你,可以随便重塑,没有后果。reset --soft 保住工作,reset HEAD~1 保住但不带暂存,只有 --hard 把它扔掉——本页唯一不保工作的动词。如果 commit 本来就不是你的、也没有任何引用指向它,最终收走它的是 git gc,不是你。

能只 stash 一个文件吗?

能——git stash push -m "wip" -- src/app.ts 只收起一条路径,树的其他部分不动。-- 分隔符就是把 stash 圈定在指定路径上的东西。单文件的边界情况——包括 stash 为什么能熬过 checkout——在 git stash a single file without losing the rest。

能 cherry-pick 多个 commit 吗?

能——用区间:git cherry-pick A^..B 按顺序取 A 之后直到 B 的每个 commit。想要它们一起进暂存区而不是逐个提交,就加 -n。麻烦区间的冲突手册在 git cherry pick: multiple commits, branches, conflicts。

如何从另一条分支 cherry-pick 多个 commit?

同一个区间写法跨分支也好使:git switch target && git cherry-pick A^..B。git 从源分支解析这些 commit 并重放到你的分支上——分支分叉的地方会有冲突,一个个解决,别一口吞。

被丢掉的 commit 还能找回来吗?

几乎总能——reflog 默认记得 HEAD 去过哪里约 90 天(git 的 gc.reflogExpire)。用 git reflog 找到丢失的 hash,然后 git reset --soft HEAD@{1} 把它放回工作区底下。你不是在撤销什么——你只是挪了一下标签,而 git 悄悄留着收据。

该用哪种 git undo?

说实话,就用上面那张表——但想让机器替你选:git-undo 生成器接收你的烂摊子,打印准确的命令;它的发布文逐例展示了推理过程。这个聚类里所有实测过的自救方法都收在 git-undo 中心。

房间里的大象:--soft、--mixed、--hard

flag 决定你的工作落在哪里,三个里只有一个危险。--soft 带暂存奉还,--mixed(默认)不带暂存,--hard 把一切对齐目标 commit 并丢弃其余。如果你已经在慌乱中敲了 --hard:reflog 还握着那个 commit 约 90 天——git reflog,然后 reset 回那个 hash。头五秒敲的动词永远决定不了结局;git 的日记比你的悔恨长。

是哪个词把你带到这儿的——undo、cancel 还是 revert?在评论区说出来;生成器三个都收,最怪的那个会成为下一篇。看板说大多数人敲的是 undo——数据先于建议存在。

$ 分享这篇文章

$ 下一篇实战指南,直达邮箱

每篇一封。修完就走。

self-hosted · 无第三方 · 一键退订

每周一封邮件。零跟踪像素。

这是什么?