撤销操作
在任何阶段,你都有可能想要撤销某些操作。Git 提供了多种撤销手段,但要注意:有些撤销操作是不可逆的,这是在 Git 中少有的会丢失工作成果的场景之一。
场景速查
| 我想要…… | 命令 |
|---|---|
| 丢弃工作区中某个文件的修改 | git restore <文件> |
| 把文件从暂存区撤回(保留修改) | git restore --staged <文件> |
| 修改最后一次提交 | git commit --amend |
| 撤销最近的提交,保留修改 | git reset --soft HEAD~1 |
| 彻底丢弃最近的提交和修改 | git reset --hard HEAD~1 |
| 撤销一个已推送的提交 | git revert <提交> |
| 找回"丢失"的提交 | git reflog |
丢弃工作区的修改
你修改了一个文件,但发现改错了,想让它回到上一次提交时的样子:
git restore app.js
# 丢弃所有文件的修改
git restore .在旧版本 Git 中等价的命令是:
git checkout -- app.js警告
这会永久丢弃工作区中尚未提交的修改,无法通过 Git 找回。执行前请确认。
取消暂存
你用 git add 把文件放入了暂存区,现在想撤回(但保留文件内容的修改):
git restore --staged app.js
# 旧写法
git reset HEAD app.js修改最后一次提交
提交后发现漏了文件,或者提交说明写错了:
# 补上遗漏的文件
git add forgotten.js
git commit --amend
# 只修改提交说明
git commit --amend -m "新的提交说明"
# 不修改提交说明
git commit --amend --no-edit--amend 会用一个新的提交替换掉原来的最后一次提交。
警告
如果最后一次提交已经推送到远程,并且其他人可能已经基于它工作,就不要再 amend 了,否则会造成历史分叉。
git reset:移动分支指针
git reset 会把当前分支指向另一个提交,根据参数不同,对暂存区和工作区的影响也不同:
| 模式 | 分支指针 | 暂存区 | 工作区 | 适用场景 |
|---|---|---|---|---|
--soft | 移动 | 保留 | 保留 | 想重新组织提交 |
--mixed(默认) | 移动 | 重置 | 保留 | 撤销提交和暂存,保留修改 |
--hard | 移动 | 重置 | 重置 | 彻底丢弃 |
# 撤销最近一次提交,修改仍在暂存区
git reset --soft HEAD~1
# 撤销最近一次提交,修改回到工作区(未暂存)
git reset HEAD~1
# 彻底回到上一个提交,丢弃之后的一切修改
git reset --hard HEAD~1
# 回退到指定提交
git reset --hard a1b2c3d
# 让本地分支和远程完全一致
git reset --hard origin/main把多个提交合并成一个
# 把最近 3 个提交合并为一个
git reset --soft HEAD~3
git commit -m "完成登录模块"git revert:用新提交撤销
reset 会改写历史,不适合用于已经推送到公共分支的提交。这时应该使用 git revert,它会创建一个新的提交来抵消指定提交的修改:
# 撤销某个提交
git revert a1b2c3d
# 撤销最近一次提交
git revert HEAD
# 撤销一个合并提交(-m 1 表示保留主线)
git revert -m 1 <合并提交>提示
记住一条原则:本地未推送的提交用 reset,已推送的提交用 revert。
找回丢失的提交:git reflog
git reset --hard 之后后悔了?别慌。Git 会在 reflog 里记录 HEAD 的每一次移动:
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: 完成登录模块
# ...
# 回到被 reset 掉的那个提交
git reset --hard e4f5g6h只要提交过的内容,在 reflog 过期(默认 90 天)之前几乎总能找回来。这也是"尽早提交、经常提交"的另一个好处。
清理未跟踪的文件
git clean 用于删除工作区中未被跟踪的文件:
# 先预览会删除什么
git clean -n
# 删除未跟踪的文件
git clean -f
# 同时删除未跟踪的目录
git clean -fd
# 连同被 .gitignore 忽略的文件一起删除
git clean -fdx警告
git clean删除的文件不在 Git 的管理范围内,无法恢复,执行前先用-n看一眼。