如何恢复 git reset --hard 删除的文件

本文详细介绍了误用Git命令`git reset --hard`导致文件丢失的问题及其解决方法,包括如何通过`git reflog`、`git fsck --lost-found`等命令找回已提交但未提交的文件,以及使用`git cat-file`命令恢复已删除的文件。文章还提供了实际操作步骤和代码示例,帮助开发者避免类似错误并快速解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天,不小心使用了下面的Git命令,结果导致了文件被删除了,花了很大力气才恢复出来。


起因:

刚提交了代码,发现还有些文件忘记提交了,于是想revert这个提交。

随便从网上搜了篇文章,然后执行 git reset --hard xxx 

结果 ... 发现工作区最近这几天的改动,新创建的文件都没有了。

$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   Linux/device_driver_pci.mm
# modified:   Linux/device_driver_pci.png
# deleted:    Linux/driver/pci/pci-config-space.png
# deleted:    Linux/driver/pci/pci_init.png
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# Linux/driver/pci/pci-config-space-260px.png
# Linux/driver/pci/pci-config-space-520px.png
# Linux/driver/pci/pci-init.png
# Linux/driver/pci/pci-pin-list.png
# Linux/driver/pci/pci-system-block-diagram.png
# Network/
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -am 'update pci driver and add network stuff'
[master 9510636] update pci driver and add network stuff
 4 files changed, 792 insertions(+), 72 deletions(-)
 rewrite Linux/device_driver_pci.png (91%)
 delete mode 100644 Linux/driver/pci/pci-config-space.png
 delete mode 100644 Linux/driver/pci/pci_init.png

$ git add Network/

$ git add Linux/driver/pci
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# new file:   Linux/driver/pci/pci-config-space-260px.png
# new file:   Linux/driver/pci/pci-config-space-520px.png
# new file:   Linux/driver/pci/pci-init.png
# new file:   Linux/driver/pci/pci-pin-list.png
# new file:   Linux/driver/pci/pci-system-block-diagram.png
# new file:   Network/MAC_PHY Interface.mm
# new file:   Network/MAC_PHY Interface.png
# new file:   Network/XAUI_XLAUI_CAUI Interface.png
#

$ git log
commit 9510636becf35f83d78622da7cbf02e9231b9e8b
Author: bambreeze <bambreeze@gmail.com>
Date:   Tue Jan 7 22:13:32 2014 +0800


    update pci driver and add network stuff


commit 1d2b02818e8faac92927048e05c0ce98ca88096c
Author: bambreeze <bambreeze@gmail.com>
Date:   Tue Dec 31 18:55:34 2013 +0800


    update pci driver


$ git reset --hard 1d2b02818e8fa
HEAD is now at 1d2b028 update pci driver
$ git status
# On branch master
nothing to commit (working directory clean)


解决办法:

当时,看到“working directory clean”,感觉就不对劲。检查了一下目录/文件,发现最近的改动全没有了,果然是干干净净啊!

所以,使用这个命令 git reset --hard 一定要小心!

第一步,从网上搜索到可以恢复到最近提交的代码

$ git reflog
1d2b028 HEAD@{0}: reset: moving to 1d2b02818e8fa
9510636 HEAD@{1}: commit: update pci driver and add network stuff
1d2b028 HEAD@{2}: commit: update pci driver
e4e042b HEAD@{3}: commit: add infrastructure of Linux pci driver
eb7ac57 HEAD@{4}: commit: update i2c driver - add at24 device
034034f HEAD@{5}: commit: update i2c linux driver - example of mini2440
17e0bfb HEAD@{6}: commit: add some diagram for i2c driver
1f382d7 HEAD@{7}: commit: update i2c driver - overview
ff6f096 HEAD@{8}: commit: update i2c driver - SMBus extention
d5bd8cf HEAD@{9}: commit: update i2c device driver - i2c stub driver
8a51d9c HEAD@{10}: commit: update i2c device driver - Multiplexed I2C bus driver
2eab503 HEAD@{11}: commit: update i2c device driver - reorgnized the blocks
e03169e HEAD@{12}: commit: update i2c device driver mindmap
0a5ffa9 HEAD@{13}: commit: add device driver for i2c subsystem
ca46ee2 HEAD@{14}: clone: from git@github.com:bambreeze/mindmap.git
$ git reset 9510636
Unstaged changes after reset:
M Linux/device_driver_pci.mm
M Linux/device_driver_pci.png
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   Linux/device_driver_pci.mm
# modified:   Linux/device_driver_pci.png
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# Linux/driver/pci/
no changes added to commit (use "git add" and/or "git commit -a")


好吧,现在恢复出了上次已经提交的东东,有了一点进展,赶快备份到另外一个地方。

可是,我还有不少已经 staged ,但是还没有提交的文件被删除了呢!

继续找办法,终于在 stackoverflow 找到了 (我估计这里也有)

If you didn't already commit your local changes (or at least stage them via git add, they're gone. git reset --hard is a destructive operation for uncommitted changes. If you did happen to stage them, but didn't commit them, try git fsck --lost-found and then search through the contents of .git/lost-found - it will contain all of the objects that aren't referenced by a known commit, and may include versions of files that were staged.

You can recover anything you git added, with git fsck --lost-found and poke around in.git/lost-foundfind .git/objects -type f | xargs ls -lt | sed 60q will give you the last 60 things to get added to the repo, that'll help. Anything you didn't git add is gone as surely as if you'd deleted it yourself.

简而言之,就是你 staged 了,但是还没有提交的东西,还是可以恢复的。具体的恢复过程,又找了篇文章(参考2)

$ find .git/objects -type f | xargs ls -lt | sed 20q
-r--r--r--  1 fazhang  staff    73399 Jan  7 22:14 .git/objects/49/a787a1cd6303cadd071724196d6f81a8ed3f2f
-r--r--r--  1 fazhang  staff    61494 Jan  7 22:14 .git/objects/63/c15d529966a5a32bf9d83868554ab557a1e3f0
-r--r--r--  1 fazhang  staff    10324 Jan  7 22:14 .git/objects/9f/630c0e1d66a119b5251694a64dfb1f6adf1235
-r--r--r--  1 fazhang  staff    45197 Jan  7 22:14 .git/objects/e1/fa99d0752478a082f6e68ce4c37f44fe64041b
-r--r--r--  1 fazhang  staff    57479 Jan  7 22:14 .git/objects/82/31f83dc25e8a1274419e1f0d53ea679f309d3f
-r--r--r--  1 fazhang  staff      891 Jan  7 22:14 .git/objects/8e/552663977d7bfa8b55b29c2262dc83e66f7c1f
-r--r--r--  1 fazhang  staff    29913 Jan  7 22:14 .git/objects/96/aef1025425ee1dccd249e3325c11ac2dbd28df
-r--r--r--  1 fazhang  staff     7106 Jan  7 22:13 .git/objects/0a/89d1a50c78874927da7b7c68587b57a6876ec1
-r--r--r--  1 fazhang  staff      175 Jan  7 22:13 .git/objects/95/10636becf35f83d78622da7cbf02e9231b9e8b
-r--r--r--  1 fazhang  staff   525702 Jan  7 22:13 .git/objects/b6/1733ec44668b4019459c03123f8f8955026eb5
-r--r--r--  1 fazhang  staff      118 Jan  7 22:13 .git/objects/d2/856654cdb7a63a9a853182b74e32761b958104
-r--r--r--  1 fazhang  staff      424 Jan  7 22:13 .git/objects/d7/54daa8cb92a0dc6afd6010ad9e38fddb4163f6
-r--r--r--  1 fazhang  staff      158 Dec 31 18:55 .git/objects/1d/2b02818e8faac92927048e05c0ce98ca88096c
-r--r--r--  1 fazhang  staff       94 Dec 31 18:55 .git/objects/86/241ce44ffe2fcdbb142b3e5e50e9397e4552f1
-r--r--r--  1 fazhang  staff      117 Dec 31 18:55 .git/objects/98/b3962e067f0d06039413d5d610afea326f83b5
-r--r--r--  1 fazhang  staff      857 Dec 31 18:55 .git/objects/bf/326b01c7693515fb2d054dbc68cd6bf869f783
-r--r--r--  1 fazhang  staff      425 Dec 31 18:55 .git/objects/ee/ca3bf3cea2234a332bec71cd15216c1c72e9a0
-r--r--r--  1 fazhang  staff     2767 Dec 31 18:55 .git/objects/00/86c082b4d9a5f82a7837bd33a4c231224eecd7
-r--r--r--  1 fazhang  staff   102764 Dec 31 18:55 .git/objects/6d/911544077e1864b54e4e4a4ea2781f2eba595e
-r--r--r--  1 fazhang  staff   244721 Dec 31 18:55 .git/objects/cd/3759406069efaaf7ad5191286025e04d95eaec




$ git cat-file -p 49a787a1cd6303cadd071724196d6f81a8ed3f2f > ~/b1.png
$ git cat-file -p 63c15d529966a5a32bf9d83868554ab557a1e3f0 > ~/abc.png
$ git cat-file -p 9f630c0e1d66a119b5251694a64dfb1f6adf1235 > ~/abc.png
$ git cat-file -p e1fa99d0752478a082f6e68ce4c37f44fe64041b > ~/abc.png
$ git cat-file -p 8231f83dc25e8a1274419e1f0d53ea679f309d3f > ~/abc.png
$ git cat-file -p 8e552663977d7bfa8b55b29c2262dc83e66f7c1f > ~/abc.mm
$ git cat-file -p 96aef1025425ee1dccd249e3325c11ac2dbd28df > ~/abc.png
$ git cat-file -p 0a89d1a50c78874927da7b7c68587b57a6876ec1 > ~/abc.txt
$ git cat-file -p 0a89d1a50c78874927da7b7c68587b57a6876ec1 > ~/abc.mm
$ git cat-file -p 9510636becf35f83d78622da7cbf02e9231b9e8b > ~/abc.txt
$ git cat-file -p b61733ec44668b4019459c03123f8f8955026eb5 > ~/abc.png
$ git cat-file -p d2856654cdb7a63a9a853182b74e32761b958104 > ~/abc.txt
$ git cat-file -p d754daa8cb92a0dc6afd6010ad9e38fddb4163f6 > ~/abc.txt


参考文献

1.  How to recover after i execute :git reset --hard HEAD


2. 

Git 内部原理 - Git 对象

<think>好的,用户想了解Git中'git reset-- .'和'gitreset --hard'的区别。首先我需要回忆reset的不同模式,比如--soft、--mixed、--hard的区别。根据引用[2],--mixed会重置HEAD和索引,而--hard还会重置工作目录。用户提到的这两个命令都属于reset的不同用法。接下来,分析'gitreset --.'。这里的'.'通常表示当前目录,可能是指定路径。根据Git文档,当使用路径时,reset只会影响索引中的特定文件,不会移动HEAD。这应该属于mixed模式,默认是--mixed,所以这个命令的作用是将暂存区的文件恢复到HEAD版本,但工作目录保持不变。用户需要明确路径的作用。 然后看'git reset--hard',根据引用[2]和[4],--hard会重置HEAD、索引和工作目录,所有未提交的更改都会被丢弃。这包括暂存和非暂存的修改,比较危险,如引用[1]提到的gitcheckout--<file>的危险性类似。需要比较两者的主要区别:一个影响特定路径的暂存区,另一个影响整个项目且彻底丢弃更改。同时,用户可能混淆了路径和模式参数的不同组合。要确保解释清楚命令的结构,比如'git reset[mode] [commit] [path]'的格式,其中模式缺省是--mixed,路径的存在会限制reset的范围。 另外,用户可能在实际使用中遇到误操作,需要强调--hard的风险,如引用[1]警告的不可逆操作。同时,可能涉及gitrestore的相关命令,如引用[1]中的git restore--staged和gitrestore,与reset的区别也需要简要说明。最后,生成相关问题时要围绕reset的不同模式、使用场景、恢复方法等,帮助用户深入理解。</think>### Git reset命令的核心区别解析 #### 1. `git reset -- .` 的功能解析 - **路径限定作用**:`.`表示当前目录,该命令仅作用于当前目录及子目录下的文件 - **默认模式**:使用`--mixed`模式(默认行为),会重置**暂存区(index)**状态到HEAD版本,但**保留工作目录的修改** - **典型场景**:误将不需要的文件`git add`后,想要撤销暂存状态但保留工作目录修改时使用 - **等价命令**:`git restore --staged .`(引用[1]) $$ \text{操作范围} = \begin{cases} \text{HEAD位置不变} \\ \text{暂存区回退到HEAD} \\ \text{工作目录保留修改} \end{cases} $$ #### 2. `git reset --hard` 的功能解析 - **全局重置**:同时重置**HEAD指针**、**暂存区**和**工作目录** - **数据风险**:会永久丢弃所有未提交的修改(包括暂存区和工作目录) - **典型场景**:彻底放弃当前分支的所有修改,恢复到某个干净的历史状态 $$ \text{操作范围} = \begin{cases} \text{HEAD移动到目标commit} \\ \text{暂存区回退到目标commit} \\ \text{工作目录完全同步} \end{cases} $$ #### 3. 核心差异对比表 | 特征 | `git reset -- .` | `git reset --hard` | |----------------------|-------------------------|-------------------------| | **HEAD位置变化** | 不移动 | 根据参数移动 | | **暂存区修改** | 重置到HEAD | 重置到目标commit | | **工作目录修改** | 保留 | 完全丢弃 | | **路径限定支持** | ✔️(仅影响指定路径) | ❌(全局操作) | | **数据风险等级** | 低 | 高(引用[1]警告) | #### 4. 典型工作流示例 ```bash # 场景1:误添加多个文件后仅撤销暂存 $ git add . $ git reset -- . # 暂存区清空,工作目录保留修改 # 场景2:彻底回退到上一个commit $ git reset --hard HEAD~1 # 所有修改丢失(引用[4]) ``` #### 5. 安全操作建议 - 使用`git stash`临时保存工作进度 - 优先尝试`git restore`命令(引用[1]) - 执行`--hard`前用`git diff HEAD > backup.patch`创建补丁备份
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值