
Git 代码回退 / 回滚命令速查
场景:代码改坏了、想撤销某次提交、想放弃未提交的改动。 本文档结合本项目实际案例整理,按「危险程度」从低到高排列。
一、先搞清楚三个概念
术语含义对应状态工作区你正在编辑的文件git status 里 M 开头的就是暂存区(index)git add 之后git status 里绿色的是**历史(HEAD)**已 git commit 的记录git log 能看到
核心心法:回退前先想清楚——你要撤销的是"未提交的改动"还是"已经提交/推送的提交"?这两类处理方法完全不同。
二、撤销「未提交」的改动(最常用、最安全)
2.1 丢弃工作区的修改(还没 add)
# 丢弃单个文件
git checkout -- app/components/Markdown.tsx
# 丢弃所有文件的修改
git checkout -- .
# 或
git restore .
2.2 丢弃已 add 但未 commit 的改动
# 从暂存区移回工作区(文件内容不变)
git restore --staged app/components/Markdown.tsx
# 同时丢弃暂存 + 工作区的修改
git checkout HEAD -- app/components/Markdown.tsx
⚠️ 以上命令永久丢弃未提交的改动,无法找回。如果改动很重要,先
git stash暂存起来:git stash # 暂存所有未提交改动(可以反悔) git stash pop # 恢复刚才暂存的改动 git stash list # 查看暂存列表
三、撤销「已提交」但「未推送」的提交(本地 commit)
3.1 reset 软回退(推荐,保留改动在工作区)
# 撤销最近 1 次提交,改动回到暂存区(文件内容还在,可以重新提交)
git reset --soft HEAD~1
# 撤销最近 1 次提交,改动回到工作区(未 add 状态)
git reset HEAD~1 # 等同 --mixed
3.2 reset 硬回退(彻底删除提交和改动)
# 彻底回退到上一版本,丢弃这次提交的所有改动(慎用!)
git reset --hard HEAD~1
💡
HEAD~1= 上一个提交,HEAD~3= 上三个,也可以直接用提交 hash:git reset --hard abc1234。
四、撤销「已推送」的提交(本次项目实际案例)⭐
场景:CSDN 风格的 Markdown 排版提交
150085e已经 push 到 GitHub / Vercel 已部署,后来决定不要了,要回退到上一版本。
4.1 推荐:git revert(生成反向提交,不改写历史)
# 撤销某个已推送的提交(自动生成一个"反向"的新提交)
git revert 150085e
# 推送回远程,Vercel 自动重新部署
git push my-blog main
特点:
- ✅ 历史完整保留(面试讲起来是"可审计的")
- ✅ 普通 push 即可,不需要 force
- ✅ 其他人/CI 不会因为历史改写而冲突
- ✅ 可以安全地针对任意一个已推送提交(不限于最后一个)
本次实际执行:
git revert --no-edit 150085e # 生成 [main 798701d] Revert "style: Markdown 排版改为 CSDN 风格..." git push my-blog main # 150085e..798701d main -> main
4.2 备选:reset + force push(改写历史,慎用)
# 回退到上一版本(本地)
git reset --hard HEAD~1
# 强制推送覆盖远程(危险!会改写远程历史)
git push --force my-blog main
# 或更安全的形式(防止覆盖别人新推的提交):
git push --force-with-lease my-blog main
特点:
- ⚠️ 改写了远程历史,禁止用于协作分支(多人共用 main 时会导致别人冲突)
- ⚠️ force push 后,Vercel 可能因为"提交未验证"等问题出幺蛾子
- ✅ 适合:单人项目、明确要抹掉某段历史的场景
💡 为什么本项目用 revert 而不是 reset --hard + force push? 因为历史已经被推送到远程且 Vercel 已部署——改写历史会破坏 Vercel 的部署追踪、GitHub 的提交记录,而且完全没必要。revert 达到同样的"代码回到上一版"效果,代价是历史里多一条 Revert 提交,干净且安全。
五、回退到"某次提交"的多个常用命令
git log --oneline -10 # 查看最近提交(拿 hash)
git show 150085e --stat # 看某次提交改了什么文件
git revert <hash> # 撤销任意一次提交(推荐)
git reset --hard <hash> # 硬回退到某次提交(丢后面的所有提交,慎用)
git diff HEAD~1 --stat # 看上一个提交和现在的差异
六、本次案例完整复盘(项目实际场景)
背景:写文章页 Markdown 排版时,先做了"专业排版重写"(提交 0e5f2b3),又按 CSDN 风格重写(提交 150085e)。用户觉得 CSDN 版本不好看,要求回退到上一版。
实际执行过程:
# 1. 先看本地状态——发现 CSDN 提交其实已经 push 到远程了
git fetch my-blog && git status -sb
# 输出: ## main...my-blog/main (本地与远程同步,说明远程已是 CSDN 版)
# 2. 确认要回退的提交内容
git show 150085e --stat
# 输出: 3 files changed(Markdown.tsx / CodeBlockCopy.tsx / globals.css)
# 3. 生成反向提交(revert)
git revert --no-edit 150085e
# 输出: [main 798701d] Revert "style: Markdown 排版改为 CSDN 风格..."
# 4. 推送,Vercel 自动部署回退版
git push my-blog main
# 输出: 150085e..798701d main -> main
结果:线上回到 CSDN 之前的排版,历史完整保留,无 force push。
七、命令速查表
需求命令丢弃未提交的单个文件改动git checkout -- <file>丢弃所有未提交改动git checkout -- .暂存未提交改动(可反悔)git stash / git stash pop撤销未推送的提交(保留改动)git reset --soft HEAD~1彻底撤销未推送的提交git reset --hard HEAD~1撤销已推送的提交(推荐)git revert <hash> + push强制覆盖远程(慎用)git push --force-with-lease查看提交历史git log --oneline看某次提交改了什么git show <hash> --stat
八、避坑要点
- 先
git status/git log再动手——确认改动是否已提交/推送,方法完全不同 git checkout --和git reset --hard不可逆——重要改动先git stash- 多人协作的项目禁用 force push——用
git revert - revert 是"再加一条提交",不是删历史——所以 push 不会失败,CI/Vercel 都正常
- 远程已部署过的东西想回退,永远优先 revert——reset+force 会让 Vercel 部署追踪混乱
评论 (0)
还没有评论,来写第一条吧~