我Git提交错了,还能改回来吗?

摘要:大家好,我是晓凡。 引子 写代码就像炒菜,锅铲一抖盐放多了还能加水,Git 提交错了也能“回锅”。 但回锅方法不对,可能把整锅菜都糊掉。 今天咱们就掰开揉碎聊聊:到底有哪些“提交错了”的场景? 每种场景到底该怎么优雅地撤回?全部给你配好命令
大家好,我是晓凡。 引子 写代码就像炒菜,锅铲一抖盐放多了还能加水,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。 解决 把东西从暂存区踢回工作区即可: # 全部撤回 git reset HEAD . # 只撤回某个文件 git reset HEAD package-lock.json 三、场景 2 commit 写错信息,或忘了加文件 A. 只想改 commit message git commit --amend -m "新的提交说明" B. 漏了文件 git add forgotten.java git commit --amend --no-edit # 不改动 message 注意:amend 会生成新的 commit-id,如果已经 push 过,就属于“改写历史”,需要强制推送(见后文)。 四、场景 3 commit 错了,但还没 push 最后一次 commit 想直接作废 # 撤回 commit,改动保留在工作区 git reset --soft HEAD~1 # 或者 git reset --mixed HEAD~1 # 默认模式,改动回到工作区 连改动都不要,彻底删除 git reset --hard HEAD~1 倒数第 N 次提交都错了 # 回退 3 个提交 git reset --hard HEAD~3 流程图 注意:--hard 会丢改动,先确认没重要代码。 五、场景 4 已经 push,但没人基于它开发 思路:先本地回退,再强制推送。 步骤 1)本地回退 git reset --hard <回退到的commit-id> 2)强制覆盖远端 git push --force-with-lease origin main 为什么用 --force-with-lease 而不是 --force? 前者会检查远端有没有人比你先 push,避免把同事的 commit 冲掉,更安全。 六、场景 5 已经 push,且同事已拉取并继续开发 此时“改写历史”会让同事陷入混乱,禁止 reset + force push。 正确姿势:用“反转提交”(revert)。 示例 # 生成一个新的 commit,把错误提交的内容“反着做一遍” git revert <错误commit-id> git push origin main 如果一次 revert 不够,可以连续 revert: git revert OLDEST_COMMIT^..NEWEST_COMMIT 流程图 main: A-B-C-D-E(错误) revert 后:A-B-C-D-E-F(撤销E) 优点:历史干净、无冲突风险;缺点:会多一个 commit,强迫症可能不爽。 七、场景 6 merge 错了,还没 push A. 刚 merge,发现合错分支 git reset --hard HEAD~1 # 直接回到 merge 前 B. merge 了很久,已产生大量后续 commit 思路:用 git revert -m 反转 merge commit。 git revert -m 1 <merge-commit-id> -m 1 表示保留 merge 的第一个父分支(通常是 main)。
阅读全文