Skip to content

Git reset 与 restore

1. resetrestore 是干什么的

Git 中:

text
reset

和:

text
restore

都可以用于“撤销”操作。

但它们处理的对象不一样。

可以先简单记住:

text
restore
主要恢复文件

reset
主要重置提交位置和暂存区

如果再细一点:

text
git restore
主要处理工作区和暂存区中的文件

git reset
主要处理 HEAD、暂存区,有时也会影响工作区

restore

2. git restore 是什么

git restore 主要用于恢复文件。

常见用途:

text
放弃工作区修改
取消 git add
从某个提交恢复文件

它更偏向:

text
文件级操作

3. 放弃工作区修改

假设:

text
main.py

已经被 Git 跟踪。

你修改了它:

bash
nvim main.py

查看:

bash
git status

可能看到:

text
Changes not staged for commit:
  modified: main.py

如果这些修改不要了:

bash
git restore main.py

Git 会把:

text
main.py

恢复到最近一次提交的状态。


4. git restore 会丢失修改

例如:

text
最近一次 commit

main.py 原始内容

你修改 main.py

执行:

bash
git restore main.py

之后:

text
你刚才的未提交修改

会被覆盖。

所以使用前建议:

bash
git diff

先看看改了什么。


5. 恢复多个文件

可以:

bash
git restore main.py app.py

恢复当前目录下所有已跟踪文件:

bash
git restore .

这里:

text
.

表示当前目录。


6. git restore --staged

假设:

bash
git add main.py

现在文件已经进入:

text
暂存区

查看:

bash
git status

可能看到:

text
Changes to be committed:
  modified: main.py

如果只是想取消:

bash
git add

可以:

bash
git restore --staged main.py

结果:

text
main.py

会离开暂存区。

但是:

text
文件中的修改仍然存在

7. restore 两个最重要的命令

放弃文件修改

bash
git restore main.py

作用:

text
工作区 → 恢复

修改会消失。


取消暂存

bash
git restore --staged main.py

作用:

text
暂存区 → 工作区

修改还在。


8. 一个完整例子

假设修改:

text
main.py

然后:

bash
git status

显示:

text
modified: main.py

执行:

bash
git add main.py

现在:

text
工作区

暂存区

如果后悔了:

bash
git restore --staged main.py

文件重新变成未暂存状态。

如果连代码修改也不要了:

bash
git restore main.py

这样修改就完全被丢弃。

所以:

text
git restore --staged main.py

取消 add

git restore main.py

放弃修改

reset

9. git reset 是什么

git reset 主要用于:

text
移动 HEAD
重置暂存区
重置工作区

它比:

text
git restore

影响范围更大。

因此使用时需要更谨慎。


10. 什么是 HEAD

Git 中:

text
HEAD

可以简单理解为:

text
当前所在的提交

例如提交历史:

text
A ← B ← C

       HEAD

当前在:

text
C

那么:

text
HEAD

就是:

text
C

11. HEAD~1

text
HEAD~1

表示当前提交的上一个提交。

例如:

text
A ← B ← C
    ↑    ↑
 HEAD~1 HEAD

同理:

text
HEAD~2

表示:

text
当前提交往前两个提交

12. git reset 三种模式

最常见:

text
--soft
--mixed
--hard

可以先记住:

模式Commit暂存区工作区
--soft回退保留保留
--mixed回退重置保留
--hard回退重置重置

reset --soft

13. git reset --soft

例如:

bash
git reset --soft HEAD~1

表示:

text
撤销最近一次 commit

但是:

text
修改仍然保留
并且仍然处于暂存区

14. --soft 示例

原来:

text
工作区
  ↓ git add
暂存区
  ↓ git commit
提交 C

执行:

bash
git reset --soft HEAD~1

之后:

text
提交 C 被撤销
但是 C 中的修改仍在暂存区

所以可以直接重新:

bash
git commit -m "new message"

15. --soft 适合什么情况

例如提交信息写错:

bash
git commit -m "udpate"

发现:

text
udpate

拼错了。

可以:

bash
git reset --soft HEAD~1

然后:

bash
git commit -m "update"

不过如果只是修改最近一次 commit 信息,更简单的是:

bash
git commit --amend

reset --mixed

16. git reset --mixed

执行:

bash
git reset --mixed HEAD~1

会:

text
撤销 commit
取消暂存
保留工作区修改

也就是说:

text
代码还在
但需要重新 git add

17. --mixed 是默认模式

下面两个命令:

bash
git reset HEAD~1

和:

bash
git reset --mixed HEAD~1

通常效果相同。

所以:

text
git reset

默认就是:

text
--mixed

18. --mixed 示例

原本:

text
main.py

git add

git commit

执行:

bash
git reset HEAD~1

之后:

text
commit 被撤销
main.py 修改仍然存在
但已经不在暂存区

查看:

bash
git status

可能看到:

text
Changes not staged for commit:
  modified: main.py

reset --hard

19. git reset --hard

例如:

bash
git reset --hard HEAD~1

会:

text
回退 commit
重置暂存区
重置工作区

也就是说:

text
提交后的修改
可能直接全部消失

这是三种模式中最危险的一种。


20. --hard 示例

假设:

text
A ← B ← C

       HEAD

执行:

bash
git reset --hard HEAD~1

变成:

text
A ← B

   HEAD

并且工作区也恢复成:

text
B

对应的状态。


21. --hard 为什么危险

因为它不仅移动:

text
HEAD

还会直接修改:

text
工作区文件

例如你有重要的未提交代码:

text
main.py

执行:

bash
git reset --hard

这些修改可能会直接丢失。

所以在执行之前一定先看:

bash
git status

以及:

bash
git diff

reset 到指定提交

22. 使用 commit hash

先查看:

bash
git log --oneline

例如:

text
9a021bc add login
713bc19 add README
27fd621 initial commit

可以:

bash
git reset --soft 713bc19

或者:

bash
git reset --mixed 713bc19

或者:

bash
git reset --hard 713bc19

具体效果取决于模式。


reset 与暂存区

23. git reset 取消暂存

以前经常使用:

bash
git reset HEAD main.py

把:

text
main.py

从暂存区移出来。

现代 Git 更推荐:

bash
git restore --staged main.py

因为语义更明确。

所以新项目中可以优先记:

bash
git restore --staged main.py

reset 到远程分支

24. git reset --hard origin/main

这是非常常见的一条命令:

bash
git fetch origin
git reset --hard origin/main

意思是:

text
让当前本地分支
完全变成远程 origin/main 的状态

25. 使用场景

例如:

text
Mac

负责开发并 push。

Linux 机器只负责同步。

Linux 本地出现:

text
修改
冲突
lazy-lock.json 变化

而这些本地修改完全不需要。

那么:

bash
git fetch origin
git reset --hard origin/main

就可以让当前分支直接和:

text
origin/main

保持一致。


26. reset --hard 不会删除未跟踪文件

这一点非常重要。

例如项目:

text
project/
├── main.py
└── test.txt

其中:

text
test.txt

是:

text
Untracked

即未被 Git 跟踪。

执行:

bash
git reset --hard origin/main

通常不会删除:

text
test.txt

因为:

text
reset

主要处理 Git 已经跟踪的内容。


27. 删除未跟踪文件需要 git clean

如果还想删除所有未跟踪文件:

bash
git clean -fd

所以完整同步流程:

bash
git fetch origin
git reset --hard origin/main
git clean -fd

效果可以理解成:

text
已跟踪文件
→ 完全按照 origin/main

未跟踪文件
→ 删除

restore 与 reset 的区别

28. 最核心区别

git restore

主要:

text
操作文件

例如:

bash
git restore main.py

恢复文件。

bash
git restore --staged main.py

取消暂存。


git reset

主要:

text
移动 HEAD
重置暂存区
必要时重置工作区

例如:

bash
git reset --soft HEAD~1

撤销 commit,但保留暂存。


29. 对比表

命令主要作用
git restore file放弃工作区修改
git restore --staged file取消暂存
git reset --soft回退提交,保留暂存和修改
git reset --mixed回退提交,取消暂存,保留修改
git reset --hard回退提交并丢弃修改

一套完整流程理解

30. Git 的三个区域

先记住:

text
工作区
   ↓ git add
暂存区
   ↓ git commit
本地仓库

那么:

restore

主要在:

text
工作区 ↔ 暂存区

之间处理文件。

reset

主要从:

text
本地仓库

往回调整:

text
HEAD
暂存区
工作区

31. 场景一:代码写错了,还没 add

状态:

text
工作区有修改

想全部不要:

bash
git restore main.py

32. 场景二:不小心 git add

执行了:

bash
git add main.py

但是暂时不想提交:

bash
git restore --staged main.py

修改仍然保留。


33. 场景三:commit 错了,但代码要留着

如果想保留暂存状态:

bash
git reset --soft HEAD~1

如果想取消暂存,但代码继续保留:

bash
git reset HEAD~1

34. 场景四:最近一次提交和代码全部不要

bash
git reset --hard HEAD~1

注意:

text
代码修改会被删除

使用前一定确认。


35. 场景五:本地完全覆盖成 GitHub 版本

bash
git fetch origin
git reset --hard origin/main

如果连未跟踪文件也要清掉:

bash
git clean -fd

revertreset

36. 已经 push 的提交不要轻易 reset

如果某个 commit:

text
已经 push 到 GitHub

并且其他人可能已经基于它继续开发,

通常不建议直接:

bash
git reset

然后强制 push。

因为这样会:

text
改写 Git 历史

多人协作时很容易造成问题。


37. git revert

对于已经共享出去的提交,更常见的是:

bash
git revert commit_hash

例如:

bash
git revert 9a021bc

它不会删除原来的提交。

而是创建一个:

text
新的 commit

用于撤销之前的修改。


38. reset 和 revert 的区别

reset

text
移动历史

例如:

text
A ← B ← C

reset 到 B:

text
A ← B

revert

原来:

text
A ← B ← C

revert C:

text
A ← B ← C ← D

其中:

text
D

负责撤销 C 的修改。

因此:

text
reset
更适合本地、尚未共享的历史

revert
更适合已经 push 的提交

常见危险命令

39. git reset --hard

bash
git reset --hard HEAD~1

可能删除:

text
未提交修改
提交后的代码

执行前至少:

bash
git status
git diff

40. git restore .

bash
git restore .

会放弃当前目录下大量未暂存修改。

所以也需要谨慎。


41. git clean -fd

bash
git clean -fd

会删除未跟踪文件和目录。

推荐先预览:

bash
git clean -nd

确认后再:

bash
git clean -fd

命令速查

42. restore

放弃一个文件修改:

bash
git restore main.py

放弃当前目录修改:

bash
git restore .

取消暂存:

bash
git restore --staged main.py

43. reset

撤销最近一次 commit,修改保持暂存:

bash
git reset --soft HEAD~1

撤销最近一次 commit,修改保留但取消暂存:

bash
git reset HEAD~1

撤销最近一次 commit,并丢弃修改:

bash
git reset --hard HEAD~1

同步远程:

bash
git fetch origin
git reset --hard origin/main

44. 最简单的记忆方法

restore

看到:

text
restore

想到:

text
恢复文件

最常见:

bash
git restore file

reset

看到:

text
reset

想到:

text
重置 Git 状态 / 提交位置

最常见:

bash
git reset --soft HEAD~1
git reset HEAD~1
git reset --hard HEAD~1

45. softmixedhard 记忆

最容易记的方式:

text
soft
最温柔
代码和暂存都留下

mixed
中等
代码留下,暂存取消

hard
最狠
代码也恢复

对应:

text
             commit   staged   working tree

--soft         ×         ✓          ✓

--mixed        ×         ×          ✓

--hard         ×         ×          ×

这里:

text
✓ = 保留
× = 重置

小结

restorereset 最核心的区别:

text
restore
主要恢复文件

reset
主要重置提交和 Git 状态

日常最常用的几个命令:

bash
git restore file

放弃未暂存修改。

bash
git restore --staged file

取消:

text
git add

但保留代码。

bash
git reset --soft HEAD~1

撤销 commit,但保留暂存。

bash
git reset HEAD~1

撤销 commit,保留代码。

bash
git reset --hard HEAD~1

撤销 commit,同时丢弃代码修改。

如果本地机器只想完全跟随远程:

bash
git fetch origin
git reset --hard origin/main
git clean -fd

最后记住:

text
不确定时先 git status
危险操作前先 git diff

特别是:

text
git restore .
git reset --hard
git clean -fd

都可能导致本地修改丢失。