如何撤销 git pull,回到之前的状态
先确认 pull 是 merge 还是 rebase,以及是否仍在进行。用 reflog 核对 pull 前提交并备份;ORIG_HEAD 可能被覆盖,reset --hard 会丢失未提交改动。
一句话回答:进行中的 merge/rebase 优先用对应的 git merge --abort / git rebase --abort。已完成的 pull 可在备份后用 reflog 找到 pull 前的提交,再决定是否 reset;ORIG_HEAD 只是候选引用,可能已被后续操作覆盖,不能未经核对就 hard reset。
最快捷的方式:ORIG_HEAD
merge/rebase 等操作可能记录原 HEAD,但后续 reset、merge 或 rebase 内部操作可能改写 ORIG_HEAD;无变化或失败的 pull 也不能保证它代表本次 pull 前的位置。
git status
git show --no-patch --oneline ORIG_HEAD
git reflog --date=iso
核对目标后,先给当前提交建救援分支(名称需未占用),再备份未提交内容:
git branch rescue-before-undo-pull
# 无冲突时可 git stash -u;冲突中无法 stash 时先在仓库外保存所需文件。
# 只有目标已核对、且可丢弃当前已跟踪改动时才执行:
git reset --hard <已核对的pull前提交>
救援分支只保存提交,不保存工作区;hard reset 还可能覆盖妨碍写入目标路径的未跟踪文件。
通用方式:reflog 定位
git reflog
# abc1234 (HEAD -> main) HEAD@{0}: pull: Fast-forward ← pull 操作
# def5678 HEAD@{1}: commit: 我上次的提交 ← pull 前位置
git reset --hard def5678
reflog 方式的好处是能看清 pull 到底做了什么(fast-forward 还是 merge),确认无误再重置。
按 pull 结果对号入座
| pull 的结果 | 撤销方法 |
|---|---|
| Fast-forward(直接快进) | 备份后 reset 到核对过的 pull 前提交 |
| 产生了合并提交 | 同上,reset 掉合并提交 |
| merge 冲突中 | 保存所需文件后 git merge --abort;原有未提交改动可能影响恢复 |
| pull = rebase 模式 | git rebase --abort(进行中)或依据 reflog 核对后 reset(已完成) |
撤销的撤销
reset 之后后悔了?reflog 里 pull 后的那条记录还在,再 git reset --hard abc1234 就回到 pull 之后的状态——前提是目标提交对象与相关记录仍存在。reflog 过期和对象清理可配置,不提供固定 90 天的恢复保证;恢复前也要备份当前未提交改动。
常见问题(FAQ)
Q:reset --hard 会不会把我 pull 之前就有的未提交改动也删了?
A:会。--hard 会覆盖已跟踪文件的工作区与暂存内容,还可能移除挡住目标路径的未跟踪文件,并非只撤销 pull 本身。pull 前有未提交改动的话,先 git stash -u 保存,撤销 pull 后再 git stash pop。
Q:pull 进来的提交已经在远程,撤销会影响别人吗?
A:不影响远程和别人——你只是把本地分支指针移回去,远程的提交还在。下次 pull 它们还会下来(这正是你要的效果:放弃本地合并结果,但远程内容不丢)。
Q:撤销 pull 后想换个方式重新合并?
A:常见诉求。reset 后按需选择:git merge --no-ff origin/main 保留合并痕迹、或 git rebase origin/main 保持线性历史。
核查依据
本文依据官方文档核对,示例未在实际业务环境运行;上线前请按部署版本、权限与数据范围验证。