上个周末遇到了一个这样的场景node
node_modules src - ...files test - test.js package.json
睡前原本准备上传到github仓库git
git init
git add -A
发现忘记添加.gitignore
,把node_modules
文件都add进去了
因而手贱输入了git reset --hard
github
而后发现...目录里的东西所有没了(只剩下.git/
文件架),shell
当时个人心里json
心急如焚懊悔不已的我,通过查阅相关资料,仍是找到了一些拯救代码的方法异步
因为每次git命令进行操做时git都会对相关文件进行快照,并经过必定形式把信息保存再.git/
目录下。ui
因为此前我使用过git add -A
命令,所以当文件被放进暂存区时,快照信息对象就已经保存了,而实用git reset --hard
以后,这些对象就变成了悬空文件对象(dangling blob
)。spa
咱们可使用git fsck
命令显示他们.net
git fsck:用于验证当前git仓库数据的有效性和一致性,可以显示那些"丢失"的commit
、blob
(文件)、tree
等。3d
咱们能够经过如下命令git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")
咱们获得一大堆blob
的hash ID
unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3 unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03 ...
接下来使用git show
就能显示这些对象的内容了,例如git show 907b308
可是因为我曾经添加的文件实在太多node_modules
里的文件可能有上千个,所以对逐个ID进行git show
肉眼筛选是很是不科学。
所以我写了个简单的nodejs脚本(由于我比较熟悉),筛选还原那些我须要的文件。
首先使用git fsck
把hash ID都存到一个文件里git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes
"use strict"; const fs = require("fs"); const shelljs = require("shelljs"); const through = require("through2"); let buf = fs.readFileSync("./allhashes") buf = buf.toString(); let hashes = [] buf.replace(/dangling blob (\w+)/gi,function (matached, hash) { hashes.push(hash) }); let all = hashes.length; let left = all; hashes.forEach(hash=>{ let fullContent = "" let stdout = shelljs.exec("git show "+hash,{silent:true}).stdout; let input = through(); console.log((left--)+"/"+all); //TODO:through2原来是为了处理stdout流的异步数据引入的,当前同步过程下不须要 input.pipe(through((buf,_,next)=>{ fullContent = fullContent+buf.toString(); next(null,buf) },flush=>{ if (matchContent(fullContent)){ fs.writeFile("./objects/"+hash,fullContent) } flush() })) input.push(stdout); input.push(null); }) function matchContent(content){ // ... 匹配规则 }
因而通过几分钟的执行,我找回了个人代码