git reset --soft HEAD~1 会移除该提交,并把所有改动重新放回暂存区,和提交前那一刻完全一样。这是常见情况下的答案。你处于哪种情况,比用哪个参数更重要。
1. 还没 push——撤销提交,保留暂存的改动
$ clai 撤销我的上一次提交,但把改动保留在暂存区→ git reset --soft HEAD~1$ git status --shortM f.txt
提交从日志中消失了,文件没有被改动,所有内容仍在暂存区。修正提交信息,或者把漏掉的文件加进来,然后重新提交。
2. 保留改动,但取消暂存
$ clai 撤销上一次提交,并把改动也从暂存区移除→ git reset HEAD~1
--mixed 是默认模式。和 soft 一样,只是多退一步:文件留在磁盘上,暂存区被清空。想把改动重新拆分成不同的提交时用它。
3. 彻底丢弃这些改动
$ clai 永久删除我的上一次提交及其所有改动→ git reset --hard HEAD~1⚠ DANGER — uncommitted changes in the working tree are destroyed
--hard 是三者中唯一会丢失工作内容的。已提交的内容可以通过 reflog 找回;而已修改但未提交的内容则不行。
4. 已经 push 过——用 revert 而不是 reset
$ clai 撤销我已经 push 过的提交,但不要改写历史→ git revert HEAD
revert 会创建一个新提交来撤销旧提交。历史保持不变,任何已经拉取过的人都不需要做任何事。在共享分支上,这是唯一正确的做法。
5. 只是想改一下提交信息
$ clai 修改我上一次提交的信息→ git commit --amend -m "Fix cache invalidation on write path"
如果暂存区是空的,--amend 只会重写提交信息。如果暂存区有内容,它也会把这些改动合并进上一次提交——很有用,但也容易不小心触发。
6. 选错了——把它找回来
$ clai 告诉我这次 reset 之前 HEAD 在哪里→ git reflog4d2e830 HEAD@{0}: reset: moving to HEAD~1dc4fa62 HEAD@{1}: commit: second4d2e830 HEAD@{2}: commit (initial): first$ git reset --hard dc4fa62
reflog 默认会记住 HEAD 90 天内所在过的每一个位置。对一个丢失的提交执行 --hard reset,可以把它原样找回来。
常见陷阱
- 永远不要对共享分支强制推送 reset。 改写别人已经拉取过的历史,会破坏他们本地的克隆。这正是
revert存在的意义。 - 这里的
HEAD~1和HEAD^是同一个东西——都是回退一个提交。它们只在合并提交上才有区别,此时HEAD^2指第二个父提交。 - push 之后再用
--amend同样会改写历史。 它会创建一个哈希值不同的新提交对象,所以同样的规则适用。
相关问题
如何撤销最近三次提交,同时保留所有改动? git reset --soft HEAD~3——这几次提交里的改动会一起进入暂存区。
reset 会永久删除提交吗? 不会立刻删除。它会变得不可达,但 reflog 默认还会指向它大约 90 天,直到垃圾回收运行。
在没有其他人使用的功能分支上,该用 reset 还是 revert? 用 reset,更干净。一旦可能有别人拉取过,就改用 revert。
相关阅读
- 用大白话说出的 git 任务:「给我看看还没 push 的提交」
- SAFE、CAUTION、DANGER:CliAI 如何给即将执行的命令分级
- 入职第一天:CliAI 如何取代「去 Slack 问资深同事」
CliAI 把 reset --hard 标记为 DANGER,并要求手动输入确认——这是唯一真正会丢失工作内容的 git 命令。一行命令安装。