1. 查找丢失数据

1
git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs] [--[no-]full] [--strict] [--verbose] [--lost-found] [--[no-]dangling] [--[no-]progress] [--connectivity-only] [--[no-]name-objects] [<object>*]

git fsck –lost-found 是一个写出文件动作,执行该命令前不会有以下 lost-found目录。执行之后会根据情况将悬挂对象写入.git/lost-found/commit/或.git/lost-found/other/

具体取决于类型。如果对象是blob,则将内容写入文件中,而不是其对象名称。

1.1. commit目录

丢失的commit信息,丢失的stash信息

1.2. other目录

add但未commit的,请看示例
add但未commit恢复方法

2. 适用场景

2.1. 误删branch

2.2. 误删stash

2.3. 切换branch丢失commit

2.4. add后未commit执行了git reset –hard

如果你没有commit你的本地修改(甚至于你都没有通过git add追踪过这些文件,当他们被删除,git reset --hard对于这些没有被commit过也没有git add过的修改来说就是具有毁灭性的
but,如果你幸运的是曾经通过git add命令追踪过这些文件,只是没有commit它们而已!那么试试git fsck --lost-found这个命令吧!然后你就可以在本地项目文件中路径为.git/lost-found/other中找到它们!!并且呢,这里面包含了所有的没有被commit(指定到某次commit)的文件,甚至可能还包括你每次git add的版本(version一词实在不知道在这里怎么翻译,姑且就认为是版本吧)!
使用git fsck –lost-found这个命令,通过.git/lost-found/other这个路径,你可以恢复任何你git add过的文件!再通过find .git/objects -type f | xargs ls -lt | sed 60q这个命令,你就可以找到最近被你add到本地仓库的60个文件
当然咯,如果你没有git add过的文件呢,被git reset –hard这个命令整过之后呢,就如你自己执行delete命令一样,再也尸骨难寻啦(也就是真的毛都不剩了!!默哀三秒)!!!!

  • q 表示退出,不再处理后续内容。比如 sed '2q' p.txt 执行到第二行后退出。

3. 演示示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mkdir recovery;cd recovery  
git init
touch file
git add file
git commit -m "First commit"
echo "Hello World" > file
git add .
git commit -m "Greetings"
git branch cool_branch
git checkout cool_branch
echo "What up world?" > cool_file
git add .
git commit -m "Now that was cool"
git checkout master
echo "What does that mean?" >> file

存储当前仓库未提交的改动,也便于后面演示如何恢复stash

1
git stash save "temp save"

3.1. 恢复误删除分支提交

现在repo里有两个branch

1
git branch

删除一个分支

1
git branch -D cool_branch

1
git log

3.2. 查看当天的丢失记录

用git fsck –lost-found命令找出刚才删除的分支里面的提交对象


或者使用下面的shell脚本

1
git fsck --lost-found 2&>/dev/null | while read i; do; git show `echo $i | cut -d ' ' -f 3` | head -n 6; done

可以看到我们丢失的分支cool_branch中的commit为9144,正是我们演示示例中的commit

值得注意的是:此时我们执行git fsck --unreachable 不会得到任何信息,因为已经删除了

3.3. commit恢复方法

3.3.1. git rebase

1
git rebase 21a2

1
git log

我们可以发现被误删分支cool_branch的提交21a2被rebase到了master分支上
但丢失的分支是无法找回的

3.3.2. git merge

为了演示git merge方法,我们使用下面的命令把上面恢复的分支提交再次删掉

1
git reset --hard HEAD^


我们可以看到丢失的分支提交仍然是21a2

执行git merge

1
git merge 21a2

1
git log

3.3.3. patch

git-format-patch将提交导出为补丁文件,然后可以将其应用于另一个分支或克隆的存储库。补丁文件表示单个提交,Git在导入补丁文件时重新提交

git-format-patch是将更改从一个存储库副本转移到另一个存储库副本的短流程中的第一步。当Git只在本地使用而没有远程存储库时,旧的方式是通过电子邮件将补丁互相发送。如果您只需要向某人提交一次提交,而不需要合并分支和随之而来的开销,那么这是非常方便的。

为方便演示,这里重新执行了3.演示示例 查找丢失commit信息如下:

漾我们把丢失的commit打成补丁

1
2
3
4
# n指从sha1 id对应的commit开始算起n个提交。
git format-patch 【commit sha1 id】-n
# eg
git format-patch e24e -1

检查patch能否正常应用

1
git apply --check 0001-Now-that-was-cool.patch


不报错就是最好的暗示🤭

应用patch

1
git apply 0001-Now-that-was-cool.patch

或者

1
git am 0001-Now-that-was-cool.patch


同样的,不报错就是最好的暗示😉

查看版本库状态git status

git add .

git commit

git log

git show c73c

查看工作区文件

查看cool_file内容

可以看到丢失的分支cool_branch上的提交,以打补丁的方式补在了master分支上

3.4. blob对象恢复

可以通过查看当天的丢失记录,也可以通过以下脚本查看最近的60次add的文件列表,然后进去查看内容

1
find .git/objects -type f | xargs ls -lt | sed 60q

我们恢复的时候只能恢复unreachable commit 开头的记录,unreach blob是不能用git statsh apply+sha-1来恢复的,会报not a stash-like commit 错误

3.4.1. 手动粘贴

1
git cat-file -p ID > a.md
1
git show eb6e >/Volumes/shaw/project/temp/1.txt

3.5. stash恢复方法

把前面演示示例stash的内容清空

1
git stash clear
1
git fsck --lost-found

也可以用git show e38f或者git cat-file -p e38f查看commit对象的具体内容

3.5.1. git merge

1
git merge e38f

因为这里的类型还是commit,git merge方法上面已经演示过,我们只演示下面的git stash apply方法

3.5.2. git stash apply

1
git stash apply e38f

值得注意的是,stash类型的commit恢复可以使用git stash apply和git merge方法,但是非stash的commit对象无法使用git stash apply方法,否则会提示以下错误信息

3.6. add但未commit恢复方法

演示准备

1
2
3
4
5
6
7
mkdir recovery;cd recovery  
git init
touch file
git add file
git commit -m "First commit"
echo "Hello World" > file
git add .

我们可以看到它是一个blog对象,这种对象是无法直接rebase或者merge或者打补丁,也没法apply,只能通过手动粘贴的方式找回自己的劳动成果,请见3.4.blob对象恢复

4. 参考

https://git-scm.com/docs/git-fsck

https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E7%BB%B4%E6%8A%A4%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D#_data_recovery

https://www.jianshu.com/p/2c900550c076

https://www.cnblogs.com/liulaolaiu/archive/2012/08/08/11744888.html