资讯专栏INFORMATION COLUMN

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

lsxiao / 2907人阅读

摘要:首先使用把都存到一个文件里原来是为了处理流的异步数据引入的当前同步过程下不需要匹配规则于是经过几分钟的执行我找回了我的代码参考链接的维护和

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

场景
自己写了大半天的一个小东西的代码,目录结构大概如下

</>复制代码

  1. node_modules
  2. src
  3. - ...files
  4. test
  5. - test.js
  6. package.json

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

git init

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仓库数据的有效性和一致性,能够显示那些"丢失"的commitblob(文件)、tree等。

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

我们得到一大堆blob的hash ID

</>复制代码

  1. unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
  2. unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03
  3. ...

接下来使用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

</>复制代码

  1. "use strict";
  2. const fs = require("fs");
  3. const shelljs = require("shelljs");
  4. const through = require("through2");
  5. let buf = fs.readFileSync("./allhashes")
  6. buf = buf.toString();
  7. let hashes = []
  8. buf.replace(/dangling blob (w+)/gi,function (matached, hash) {
  9. hashes.push(hash)
  10. });
  11. let all = hashes.length;
  12. let left = all;
  13. hashes.forEach(hash=>{
  14. let fullContent = ""
  15. let stdout = shelljs.exec("git show "+hash,{silent:true}).stdout;
  16. let input = through();
  17. console.log((left--)+"/"+all);
  18. //TODO:through2原来是为了处理stdout流的异步数据引入的,当前同步过程下不需要
  19. input.pipe(through((buf,_,next)=>{
  20. fullContent = fullContent+buf.toString();
  21. next(null,buf)
  22. },flush=>{
  23. if (matchContent(fullContent)){
  24. fs.writeFile("./objects/"+hash,fullContent)
  25. }
  26. flush()
  27. }))
  28. input.push(stdout);
  29. input.push(null);
  30. })
  31. function matchContent(content){
  32. // ... 匹配规则
  33. }

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

参考链接

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

Recovering Git repository from objects only

Git的维护(git gc和git fsck)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38052.html

相关文章

  • 关于git删除远程commit

    摘要:很多原因可能会导致我们想删掉远程服务器上提交的版本。下面主要说一下删除的命令行。然后通过命令提交到远程库。这里一定要注意注意再注意注意提交到远程库之后,的代码会直接从远程库里面删除。,代表的是最新版本的上一个版本,以此类推。 额,怎么开头呢,从文章的定位开始吧。这篇文章的目的就是定位给完全的小白,像我这样,对于互联网知识不了解的人,但是特别渴望学习,小白文章小白文章小白文章!重要的事情...

    guqiu 评论0 收藏0
  • Git 基本命令,你都学废了吗

    摘要:掌握了命令行,使用图形化工具如探囊取物。管理的文件状态已修改已暂存已提交。由于我们使用了命令,但并未创建新的分支,所以创建了一个匿名分支。省略远程分支名表示将本地分支推送到与之存在追踪关系的远程分支通常同名。概述此篇博文意在让新手快速上手 Git,满足工作中的基本需求,而非梳理细节。后续会再开一个系列,来探讨 Git 细节问题。一、Git 的安装这部分网站上资料非常多,根据自己的系统版本查找...

    Tecode 评论0 收藏0

发表评论

0条评论

lsxiao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<