事故经过
有一个项目,最早的备份是去年10月份。过去一直没进行版本控制,今天想提到码云上。我是这么做的:
git init
git add -A
- 咦,一些上传文件怎么也加进去了,忘了把上传目录加进.gitignore,想了几秒钟,果断执行了
git reset --hard
然后项目目录下就只剩几个空目录了,欲哭无泪。
绝境中的曙光
一翻搜索,发现自己还算幸运,因为之前执行过git add
。按网上的说法执行git fsck --lost-found
之后,.git/lost-found/other下多出了一堆文件名由0-9a-f组成长度为40无扩展名的文件,就是```git add``的那一堆。打开其中几个文件,二进制的分辨不出来,代码的自己肯定是能看出来个大概了。
找到这些文件的原始位置及文件名就可以恢复了。又是一翻搜索,无果。
但想来自去年10月份至现在,虽然过去了近9个月,但我应该没改太多代码。不然我先把备份恢复了,然后逐一对比?然而,居然有近12000个文件!其中包括ThinkPHP源码,及一万个gif验证码。不过不用着急,我改的文件不是少嘛,如果写段程序把项目中的每个文件都进行md5校验,然后.git/lost-found/other下那堆文件也算出md5,一样的就认为没修改过,那么剩下的那些就是我做过改动的,也就好办了。
验证一下
把备份恢复了,先把项目推到码云。然后复制一份.git/lost-found/other,写程序把other下的未改动过的文件移出。程序如下:
import os, hashlib
def restore(old_dir, new_dir, dist_dir):
old_dict = {}
new_dict = {}
get_file_md5_dict('', old_dir, old_dict)
get_file_md5_dict('', new_dir, new_dict)
for (md5, filename) in new_dict.items():
if md5 in old_dict:
src_path = os.path.join(new_dir, filename)
dict_path = os.path.join(dist_dir, old_dict[md5])
move_file(src_path, dict_path)
def get_file_md5_dict(dir, root_dir, file_dict):
current_path = os.path.join(root_dir, dir)
file_list = os.listdir(current_path)
root_len = len(root_dir)
for path in file_list:
full_path = os.path.join(current_path, path)
sub_path = full_path[root_len:]
if os.path.isfile(full_path):
md5 = md5sum(full_path)
file_dict[md5] = sub_path
elif os.path.isdir(full_path):
get_file_md5_dict(sub_path, root_dir, file_dict)
return file_dict
def move_file(src_path, dict_path):
dir = os.path.dirname(dict_path)
if not os.path.exists(dir):
os.makedirs(dir)
os.rename(src_path, dict_path)
def md5sum(filename):
md5 = hashlib.md5()
f = open(filename, 'rb')
while True:
b = f.read(1024)
if not b:
break
md5.update(b)
f.close()
return md5.hexdigest()
if __name__ == '__main__':
restore('/Users/thornbird/dev/projects2/guru/',
'/Users/thornbird/Desktop/other/',
'/Users/thornbird/Desktop/other2/')
长出一口气
一通操作猛如虎(猛不过git reset --hard
),程序执行的挺快,执行完以后other目录还剩20个文件。这就好说了。
一一打开对比确认,找出修改过的13个文件,包括.php、.html、.js、.css,小心翼翼改名替换了;1个.gitignore文件,直接删掉;还有6个二进制文件,全部改名为png,是上传过的文件,也删掉。
劫后余生的感觉,憋了一泡尿都没顾的上去厕所。