如何从 git reset --hard 中拯救代码

上个周末遇到了一个这样的场景

场景

自己写了大半天的一个小东西的代码,目录结构大概如下
node_modulessrc  - ...filestest  - test.jspackage.json

睡前本来准备上传到github仓库

  1. git init

  2. git add -A

发现忘记添加.gitignore,把node_modules文件都add进去了
于是手贱输入了git reset --hard

然后发现...目录里的东西全部没了(只剩下.git/文件架),

当时我的内心

挽救

心急如焚懊悔不已的我,经过查阅相关资料,还是找到了一些拯救代码的方法

由于每次git命令进行操作时git都会对相关文件进行快照,并通过一定形式把信息保存再.git/目录下。

由于此前我使用过git add -A命令,因此当文件被放进暂存区时,快照信息对象就已经保存了,而实用git reset --hard之后,这些对象就变成了悬空文件对象(dangling blob)。

我们可以实用git fsck命令显示他们

git fsck:用于验证当前git仓库数据的有效性和一致性,能够显示那些"丢失"的commit、blob(文件)、tree等。

我们可以通过以下命令
git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")

我们得到一大堆blob的hash ID

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3unreachable 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){    // ... 匹配规则}

于是经过几分钟的执行,我找回了我的代码

参考链接

  1. Undo git reset --hard with uncommitted files in the staging area

  2. Recovering Git repository from objects only

  3. Git的维护(git gc和git fsck)

关键字:git, bash, node.js, Python


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部