posts

Git 撤销未推送的提交

撤销本地已提交但还没 push 的提交的操作流程:先查清楚有哪些未推送提交,再按是否保留工作区改动选择 reset 模式。

本地已经 commit、但还没 push 的提交,可以直接用 git reset 把分支指针移回去,不会产生新提交,也不会影响远程。下面是一套可直接照搬的操作流程。

一、先查清楚有哪些未推送的提交

动手前务必确认范围,尤其是有 merge 提交时,“领先 N 个提交” 这个数字可能是虚高的。

# 1. 看本地领先远程多少
git branch -vv | grep "^\*"

# 2. 列出未推送的提交(区分 merge / 非 merge)
git log --oneline origin/当前分支..HEAD
git log --oneline --no-merges origin/当前分支..HEAD

# 3. 确认远程和本地各自指向哪
git log -1 --oneline origin/当前分支
git log -1 --oneline HEAD

# 4. 看工作区有没有未提交改动(决定用哪种 reset)
git status

坑点:如果最近做过 merge(比如 Merge origin/dev into feature/xxx),git log origin/分支..HEAD 会把 merge 带进来的那一大堆提交也算进去,可能显示“领先 90+”,但其中真正属于你的新提交往往只有最顶上那一个 merge。

二、执行回退

把分支指针移回远程最新点,等于撤销所有未推送的提交:

# --mixed 为默认行为,可省略
git reset origin/当前分支

三、验证结果

# 确认 HEAD 落点
git log -1 --oneline HEAD

# 与远程的差异,期望输出 0 0(不领先也不落后)
git rev-list --left-right --count origin/当前分支...HEAD

四、关键决策点:选哪种 reset 模式

git reset 有三种模式,区别在于对暂存区和工作区的处理:

场景 命令 效果
只想撤销提交,文件一个不动 git reset --soft origin/分支 指针回退,暂存区 / 工作区原样保留,改动变成“已暂存”
撤销提交 + 清空暂存区,文件保留 git reset origin/分支(=--mixed 改动变成“未暂存”,可重新挑选要提交的内容
彻底丢弃提交和工作区改动 git reset --hard origin/分支 工作区完全恢复到远程状态,不可恢复(未跟踪文件不受影响)

目标位置的选择:

  • origin/分支 = 直接对齐远程最新;
  • HEAD~1 = 只退一步(本地领先很多、但只想退最近一个提交时用)。

五、记住三点

  1. 先查清楚再动手git log origin/分支..HEAD 看准到底有几个真未推送的提交,别被 merge 制造的虚高数字误导。
  2. 有未提交改动时慎用 --hard:它会连带丢弃工作区改动,不可逆。
  3. 后悔了能找回:短期内用 git reflog 拿到刚才被撤销的 commit hash,再 git reset --hard <hash> 即可恢复。