找回密码
 立即注册
首页 业界区 业界 Git提交错了,别慌!还有后悔药

Git提交错了,别慌!还有后悔药

仰翡邸 5 小时前
大家好,我是晓凡。
引子
写代码就像炒菜,锅铲一抖盐放多了还能加水,Git 提交错了也能“回锅”。
但回锅方法不对,可能把整锅菜都糊掉。
今天咱们就掰开揉碎聊聊:到底有哪些“提交错了”的场景?
每种场景到底该怎么优雅地撤回?全部给你配好命令、画好流程,照着抄就行。
一、先分清“锅”在哪儿

首先我们得分清“锅”在哪儿,本地还是远程?
Git 把仓库分成三大块:

  • 工作区(Working Directory):你电脑上看得见的文件夹。
  • 暂存区(Index / Stage):git add 之后放东西的地方。
  • 本地仓库(Local Repo):git commit 之后放东西的地方。
  • 远程仓库(Remote Repo):GitHub、GitLab、gitee 等远端服务器。
搞错一次提交,先问自己一句:
“锅”现在停留在哪一层?

  • 只在工作区?
  • 只在暂存区?
  • 已经 commit 但还没 push?
  • 已经 push?
  • 甚至 push 完别人已经拉下来继续开发了?
不同位置,撤回姿势完全不同。下面分场景,逐个拆招。
二、场景 1

add 错了,还没 commit
症状
git add 了不该 add 的文件,比如把 node_modules 也扔进去了,但还没 commit。
解决
把东西从暂存区踢回工作区即可:
  1. # 全部撤回
  2. git reset HEAD .
  3. # 只撤回某个文件
  4. git reset HEAD package-lock.json
复制代码
1.png

三、场景 2

commit 写错信息,或忘了加文件
A. 只想改 commit message
  1. git commit --amend -m "新的提交说明"
复制代码
B. 漏了文件
  1. git add forgotten.java
  2. git commit --amend --no-edit   # 不改动 message
复制代码
2.png

注意:amend 会生成新的 commit-id,如果已经 push 过,就属于“改写历史”,需要强制推送(见后文)。
四、场景 3

commit 错了,但还没 push

  • 最后一次 commit 想直接作废
  1. # 撤回 commit,改动保留在工作区
  2. git reset --soft HEAD~1
  3. # 或者
  4. git reset --mixed HEAD~1   # 默认模式,改动回到工作区
复制代码

  • 连改动都不要,彻底删除
  1. git reset --hard <回退到的commit-id>HEAD~1
复制代码

  • 倒数第 N 次提交都错了
  1. # 回退 3 个提交
  2. git reset --hard <回退到的commit-id>HEAD~3
复制代码
流程图
3.png

注意:--hard 会丢改动,先确认没重要代码。
五、场景 4

已经 push,但没人基于它开发
思路:先本地回退,再强制推送。
步骤
1)本地回退
  1. git reset --hard <回退到的commit-id>
复制代码
2)强制覆盖远端
  1. git push --force-with-lease origin main
复制代码
为什么用 --force-with-lease 而不是 --force?
前者会检查远端有没有人比你先 push,避免把同事的 commit 冲掉,更安全。
4.png

六、场景 5

已经 push,且同事已拉取并继续开发
此时“改写历史”会让同事陷入混乱,禁止 reset + force push。
正确姿势:用“反转提交”(revert)。
示例
  1. # 生成一个新的 commit,把错误提交的内容“反着做一遍”
  2. git revert <错误commit-id>
  3. git push origin main
复制代码
如果一次 revert 不够,可以连续 revert:
  1. git revert OLDEST_COMMIT^..NEWEST_COMMIT
复制代码
流程图
main: A-B-C-D-E(错误)
revert 后:A-B-C-D-E-F(撤销E)
5.png

优点:历史干净、无冲突风险;缺点:会多一个 commit,强迫症可能不爽。
七、场景 6

merge 错了,还没 push
A. 刚 merge,发现合错分支
  1. git reset --hard <回退到的commit-id>HEAD~1   # 直接回到 merge 前
复制代码
B. merge 了很久,已产生大量后续 commit
思路:用 git revert -m 反转 merge commit。
  1. git revert -m 1 <merge-commit-id>
复制代码
-m 1 表示保留 merge 的第一个父分支(通常是 main)。
6.png

八、场景 7

rebase 错了,想反悔
rebase 过程中冲突太多,想直接放弃:
  1. git rebase --abort
复制代码
已经 rebase 完但后悔了:
  1. # 查看 reflog 找到 rebase 前的 HEADgit refloggit reset --hard <回退到的commit-id>HEAD@{2}
复制代码
九、场景 8

cherry-pick 错了
  1. # 撤销刚 cherry-pick 的 commit
  2. git cherry-pick --abort
复制代码
如果已经 commit,可用 revert 回滚单个 cherry-pick 的 commit。
7.png

十、万能后悔药:reflog

Git 在本地会记录每一次 HEAD 的移动。
不管 reset、rebase、merge 玩得多花,只要没 gc,都能找到“案发前”的位置。
  1. git reflog# 找到想回去的 idgit reset --hard <回退到的commit-id>9f3e2a1
复制代码
8.png

十一、一张总览流程图

9.png

十二、踩坑小贴士


  • 任何 reset --hard 前,先 stash 或备份分支:git branch backup。
  • 多人协作时,默认“不能强推”,可在服务端开启保护分支。
  • 强制推送后,通知团队所有人执行 git pull --rebase 同步。
  • 重要操作前,用 git log --oneline --graph 看一眼历史,心中有数。
  • 养成 commit 粒度细、消息清晰的习惯,能减少 80% 回滚需求。
十三、记住这一句话

add 错了 reset
commit 错了 amend/reset
push 错了先问队友,没人用就 force,有人用就 revert。
实在搞不清,reflog 带你穿越回过去。
祝你再也不用“删库跑路”,回滚也能优雅如风。
我是晓凡,再小的帆也能远航
本期内容就到这儿
我们下期再见ヾ(•ω•`)o (●'◡'●)

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册