Git Rollback, Reset and Restore的使用

1. 这篇文章解决什么问题?

日常写代码时,Git 最常见的压力不是"怎么提交",而是:

text 复制代码
1. 文件改错了,怎么撤回?
2. 已经 git add 了,怎么从暂存区拿出来?
3. commit 写错了,怎么修改?
4. 已经提交了好几次,怎么回到之前的版本?
5. reset、restore、revert 到底有什么区别?

这篇只讲本地回退和撤销。

远程分支、push 被拒绝、pull --rebase 这类问题,统一放在 0205 里理解。


2. 回退前先看清楚当前状态

任何回退操作之前,先执行:

bash 复制代码
git status
git log --oneline --graph --decorate --all

前者看工作区和暂存区:

text 复制代码
哪些文件被改了
哪些文件已经 add
哪些文件还没有被 Git 跟踪

后者看提交历史:

text 复制代码
当前 HEAD 在哪里
分支指向哪个 commit
想回到哪个 commit

不要在没看清状态时直接 reset --hard


3. 三类"撤销"要分清楚

Git 里的撤销大致分三层:

text 复制代码
工作区撤销:文件还没 add,只想丢掉当前修改
暂存区撤销:文件已经 add,但不想让它进入下一次 commit
提交历史撤销:commit 已经生成,需要改历史或新增一个反向提交

对应常见命令:

text 复制代码
git restore
git restore --staged
git reset
git commit --amend
git revert

这些命令解决的问题不一样,不能只靠"撤销"两个字混着用。


4. 撤销工作区修改

如果文件还没有 git add,只是工作区改错了,可以执行:

bash 复制代码
git restore README.md

这表示:

text 复制代码
把 README.md 恢复到当前 HEAD 中记录的版本
丢弃工作区里这个文件的未暂存修改

如果要撤销当前目录下所有已跟踪文件的工作区修改:

bash 复制代码
git restore .

注意:

text 复制代码
git restore 不会恢复没有被 Git 跟踪的新文件

也就是说,Untracked files 里的文件不会因为 git restore . 自动消失。


5. 取消暂存区内容

如果已经执行过:

bash 复制代码
git add README.md

但后来发现暂时不想提交它,可以执行:

bash 复制代码
git restore --staged README.md

它的意思是:

text 复制代码
把 README.md 从暂存区拿出来
但保留工作区里的修改

也就是说,文件内容不会丢,只是下一次 commit 不再包含它。

常见流程:

bash 复制代码
git status
git restore --staged README.md
git status

这样能清楚看到文件从:

text 复制代码
Changes to be committed

回到:

text 复制代码
Changes not staged for commit

6. 同时撤销暂存区和工作区

如果一个文件已经 git add,并且你确定这些修改都不要了,可以分两步:

bash 复制代码
git restore --staged README.md
git restore README.md

第一步:

text 复制代码
从暂存区拿出来

第二步:

text 复制代码
丢掉工作区修改

更推荐新手这样写,因为每一步都能通过 git status 看清楚变化。


7. 修改最近一次 commit

如果刚刚提交完,发现 commit message 写错了:

bash 复制代码
git commit --amend -m "docs(git): update rollback note"

如果发现漏了一个文件:

bash 复制代码
git add README.md
git commit --amend

这会把暂存区里的内容合并进最近一次 commit。

需要注意:

text 复制代码
amend 会生成一个新的 commit
它不是在原地修改旧 commit

如果这次 commit 还没有 push,通常没什么问题。

如果已经 push 到远程,并且别人可能已经基于它继续开发,就不要随便 amend。


8. git reset 是什么?

reset 的核心动作是:

移动当前分支指针。

假设当前历史是:

text 复制代码
A -- B -- C -- D
               |
             main
             HEAD

执行:

bash 复制代码
git reset --soft C

或者:

bash 复制代码
git reset --mixed C
git reset --hard C

本质上都是让 mainD 移回 C

text 复制代码
A -- B -- C
          |
        main
        HEAD

区别在于:

text 复制代码
commit 指针移动后,工作区和暂存区怎么处理

9. reset --soft

执行:

bash 复制代码
git reset --soft HEAD~1

表示:

text 复制代码
撤销最近一次 commit
但把这次 commit 的内容保留在暂存区

适合场景:

text 复制代码
commit message 写错了
几个 commit 想重新整理成一个
刚提交完发现还想补一点内容

执行后通常会看到:

text 复制代码
Changes to be committed

说明修改还在暂存区,下一次可以重新 commit。


10. reset --mixed

reset 默认就是 --mixed

bash 复制代码
git reset HEAD~1

等价于:

bash 复制代码
git reset --mixed HEAD~1

它表示:

text 复制代码
撤销最近一次 commit
把这次 commit 的内容放回工作区
暂存区清空

适合场景:

text 复制代码
刚才提交太急了
想重新选择哪些文件进入下一次提交

执行后通常会看到:

text 复制代码
Changes not staged for commit

11. reset --hard

执行:

bash 复制代码
git reset --hard HEAD~1

表示:

text 复制代码
撤销最近一次 commit
丢掉对应的工作区和暂存区内容
让文件状态直接回到目标 commit

这是最危险的一种。

适合场景很少:

text 复制代码
你非常确定最近的提交和修改都不要了
当前修改没有任何保留价值
你已经确认没有未保存的重要内容

执行前至少先看一眼:

bash 复制代码
git status
git log --oneline

如果只是想取消暂存或撤销某个文件,通常不需要 reset --hard


12. HEAD~1 是什么意思?

常见写法:

bash 复制代码
git reset --soft HEAD~1

这里的 HEAD~1 表示:

text 复制代码
当前提交的上一个提交

类似地:

text 复制代码
HEAD~2  当前提交往前数两个提交
HEAD~3  当前提交往前数三个提交

也可以直接写 commit hash:

bash 复制代码
git reset --mixed a8c912e

意思是回到 a8c912e 这个提交。


13. git revert 是什么?

revertreset 很不一样。

reset 是移动分支指针,可能改写历史。

revert 是新增一个提交,用来抵消之前某个提交的修改。

例如历史是:

text 复制代码
A -- B -- C -- D
               |
             main

执行:

bash 复制代码
git revert C

可能得到:

text 复制代码
A -- B -- C -- D -- E
                    |
                  main

其中 E 是一个新的提交,它的内容用来撤销 C 带来的修改。


14. reset 和 revert 怎么选?

简单判断:

text 复制代码
本地提交,还没 push,想整理历史:可以 reset
已经 push 到远程,别人可能看到了:优先 revert
多人共享分支上要撤销某次提交:优先 revert

原因是:

text 复制代码
reset 会改变分支历史
revert 不改旧历史,只追加新历史

在团队协作里,revert 往往更稳。


15. 删除未跟踪文件

git restore 不会删除未跟踪文件。

如果想查看哪些未跟踪文件会被删除,可以先执行:

bash 复制代码
git clean -n

真正删除:

bash 复制代码
git clean -f

删除未跟踪目录:

bash 复制代码
git clean -fd

注意:

text 复制代码
clean 删除的是 Git 还没有跟踪的文件
删除后通常不能靠 Git 找回来

所以新手更推荐先用 git clean -n 预览。


16. 一个比较稳的回退流程

当你不知道该用哪个命令时,按这个顺序判断:

text 复制代码
1. 先 git status 看文件状态
2. 如果只是没 add 的文件改错了,用 git restore <file>
3. 如果已经 add 但不想提交,用 git restore --staged <file>
4. 如果最近一次 commit 写错了,并且还没 push,用 git commit --amend
5. 如果本地几个 commit 想重来,用 git reset --soft 或 --mixed
6. 如果已经 push 到共享分支,优先 git revert

不要一上来就:

bash 复制代码
git reset --hard

这个命令不是"万能撤销键",它更像是"我确认这些修改都不要了"。


17. 总结

restore 主要处理工作区和暂存区,reset 主要移动分支指针并可能改写历史,revert 通过新增提交来撤销旧提交。

回退前先 git status,再决定要动的是文件、暂存区,还是提交历史。

相关推荐
AIMath~1 小时前
git管理代码仓库的工具
git
techdashen6 小时前
为 Agent 重新设计的 Git:Cloudflare Artifacts 是什么,怎么工作的
git
赖在沙发上的熊7 小时前
Git多仓库协作中和并冲突问题:“不相关历史合并”+“问跟踪文件冲突”
git
风若飞7 小时前
▎ 适用于完全没有 Git 经验的新手
git
时空自由民.9 小时前
git rebase简介
git
山西瀚辰信安科技有限公司10 小时前
git下载安装及使用
git·学习
梓沂11 小时前
pycharm Git 连接 GitHub 报错全记录:从 SSL 证书到 SSH 密钥,一步步踩坑与解决
git·pycharm·github
无小道11 小时前
Git版本控制及其原理:从入门到精通
git·企业
颂love11 小时前
Git的简单学习
git·学习