git reset --hard 引发的灾难

事情起因

早上合代码的时候,get merge 解决完代码冲突后,迷迷糊糊敲下了git add .

git status 一看把一些还没写好的文件也add到merge的分支里了, 情急之下,立马

git log -n 1 
git reset --hard sha1

重新合并add commit push 一顿操作完事后美滋滋地去新需求评审了

直到下午需要切分支回来继续开发时发现不对了,咦我写的代码哪去了?

git status 没有
git stash list 也没有

这时候预感有点不对,马上history | grep git 看了一下 然后傻掉了git reset hard sha1恢复时,把add的内容直接覆盖掉,也就是说写的代码找不到了!!!

尝试恢复

马上谷歌搜救命的办法,对下面几种办法一一进行了尝试

1.
用git log 查找commit 然后回退到merge之前的commit
这里我的代码只执行了git add, 没有进行commit 因此这种方式没有效果

2.
git fsck --lost-found 后去 .git/lost-found/other中找代码
去看了一下,里面的有一堆文件
00f757ab1e7011d658e497eea0c2c9e67218c6c6
0a4fc242825d73e32ab9d3e2aeee98651ec6fab3
打开后看到里面是之前merge的其他分支上的代码,并不是我add的未提交的代码

3. 
find .git/objects -type f 
查找早上的文件obj对应的哈希
再借助git cat-file -p sha1 读取内容

find .git/objects -type f | xargs ls -lt | sed 136q | awk '{gsub(".git/objects/", "", $9);gsub("/","",$9);print $9}' | tee obj

用脚本从obj的sha1中dump出内容, 这里用了lua

f = io.open("obj", "r")
local line = f:read("*l")
while line do
    cmd = "git cat-file -p " .. line
    dump_file = io.open("files/" .. line, 'w+')
    local ret = io.popen(cmd)
    for line in ret:lines() do
        dump_file:write(line .. '\n')
    end
    dump_file:close()
    line = f:read("*l")
end

f:close()

执行lua dumpfromsha1.lua 后files文件夹中出现了136个sha1对应的obj的内容 然后从文件夹中grep 内容

[aidu35@aidu35 ~/workspace/odcp-console/extract/files]$ grep "scan_unused" *
6d73eae999ed1d21288524a3b2f48d47b78dee7f:local function scan_unused(dst_dir, required_path_arr)
6d73eae999ed1d21288524a3b2f48d47b78dee7f:        scan_unused(dst_dir, required_path_arr)
76f7d1d575e7c2d205446cbd8441bb23224f1baf:100644 blob 6d73eae999ed1d21288524a3b2f48d47b78dee7f	scan_unused.lua

打开6d73eae999ed1d21288524a3b2f48d47b78dee7f, 熟悉的代码又回来啦,只要改一下名字就可以了

一点反思:

git add <path>会将path下的文件加入的索引库中
这时候我们通过 git status 可以看到path目录的文件全部变成了stage状态
[gerrard@centos ]$ git add .
[gerrard@centos ]$ git status .
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   logs/access.log
#	new file:   logs/dev-error.log
#	new file:   logs/error.log
#	new file:   test/openresty-websocket-subpub.md

git 实际已经给了unstage的方法,只要git reset HEAD <path>就可以撤销了

[gerrard@centos ]$ git reset HEAD .
[gerrard@centos ]$ git status .
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	logs/
#	test/openresty-websocket-subpub.md
nothing added to commit but untracked files present (use "git add" to track)

其实 对于只add解决冲突的文件的时候,我们应该执行

git add -u .

表示把中所有tracked文件中被修改过或已删除文件的信息添加到索引库。它不会处理untracted的文件

还是因为对git命令不熟悉,忙活了两小时,值得反思记录。


wechat
微信扫一扫,订阅我的博客动态^_^