Git 如何撤销上一次提交

四种情况,四条命令。在下面找到和你处境相同的那一句,复制它下面的命令。第零条规则:已经推送了?用 revert。其余方法都假设这个提交还只在本地。

🎙️ 发布并录制于: ·

保留这些修改,还是直接扔掉

如果提交还在本地,先决定它带的那些文件该怎么办。soft reset 只撤掉提交,所有修改留在暂存区,所以当你打算重新提交时,它是正确的默认选择。hard reset 撤掉提交,还会把工作区文件变回上一个快照的样子。别只因为“撤销”这个词听起来干脆,就顺手用了 hard reset。

# "Undo the commit, KEEP my changes" — most common:
git reset --soft HEAD~1

# "Undo the commit AND throw away the changes":
git reset --hard HEAD~1

# Last N commits, with all changes staged as one pile:
git reset --soft HEAD~3
真实报错:这个提交没有父提交fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.

运行 git log --oneline。如果只显示一个提交,那就没有更早的快照可以给 reset 当目标。文件先留着,如果你真的需要一段全新历史,就建一个孤立分支,否则直接修订这第一个提交。多敲几个波浪号,造不出一个不存在的父提交。

改提交说明,或者补上漏掉的文件

amend 会用一个改好的提交替换掉最新那一个。提交说明里有错字,或者忘了暂存某个文件,用它。提交哈希会变,所以只有这个提交还属于你、还没推出去的时候,amend 才算干净。如果队友可能已经拿到了旧哈希,那就新建一个提交。

# The content is right; only the message is wrong:
git commit --amend -m "the message I meant to write"

# Add a forgotten file without changing the message:
git add forgotten.py
git commit --amend --no-edit
真实报错:没有可以修订的东西fatal: You have nothing to amend.

看一下 git log --oneline。你要么在一个还没有任何提交的仓库里,要么在一个尚未诞生的分支上。先把文件暂存,正常做出第一个提交;只有 HEAD 已经指向某个提交时,amend 才有效。

已经推送了:用 revert,不要改写历史

revert 会读取一个已有的提交,再造一个做相反改动的新提交。这样公开历史保持完整,已经拉过代码的队友也不用去修自己的分支。在共享分支上,我宁愿去解释一个不好看的 revert 提交,也不想解释为什么强制推送之后某人的工作不见了。

git revert HEAD
# creates a new commit that cancels the latest one; then push it

git revert abc1234
# same operation for an older commit by hash
如果 revert 因为冲突停下来error: could not revert abc1234... Remove broken validation
hint: after resolving the conflicts, mark the corrected paths with 'git add <paths>'

运行 git status,打开每个未合并的文件,留下你希望 revert 之后代码呈现的那个版本,删掉冲突标记,然后对每个文件运行 git add,再执行 git revert --continue。想放弃这次操作、回到 revert 之前的状态,运行 git revert --abort

reset --hard 之后,用 reflog 找回来

hard reset 移动的是分支标签,Git 通常还留着那个旧的提交对象。reflog 记录了 HEAD 曾经指向过哪些地方。先读这些记录,找出 reset 之前的那个提交,必要时先看一眼它的内容,然后才往回走。别默认上一条记录就一定是你要的那个,别的命令可能又写进了更新的 reflog 记录。

git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# f4e5d6c HEAD@{1}: commit: the one you want back

git show f4e5d6c             # inspect before moving anything
git reset --hard f4e5d6c     # restore that exact commit
# equivalent here: git reset --hard HEAD@{1}
速查表保留修改:reset --soft HEAD~1 · 丢弃修改:reset --hard HEAD~1 · 改最新那个提交:--amend · 已经推送:revert HEAD · 找回来:reflog
本页是我们 Git 系列中的一篇。想弄懂三棵树的心智模型并听完整讲解,请读 10 分钟学会 Git →

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.