如何恢复由于不正确的.gitattributes而损坏的PNG文件?

时间:2019-03-25 03:16:57

标签: git png gitattributes

我添加并提交了一些PNG文件并将其推送到我的git repo中,但是不幸的是,我有一个不正确的.gitattributes文件,如下所示:

* text
# no settings for PNG files

git将PNG文件视为文本文件。现在,我无法再打开它们,并且我也丢失了它们的原始副本。有什么办法可以恢复它们?谢谢!


更新:添加PNG文件时,.gitattributes已在存储库中。这意味着我在提交历史记录中找不到PNG文件的 good 状态。而且所有提交都在Windows上完成。

2 个答案:

答案 0 :(得分:3)

让我们假设您有2次提交:

  • 在第一个文件中,所有PNG文件均以二进制格式处理,这些文件都是声音。
  • 第二次提交包含.gitattributes文件,所有PNG文件都被损坏,因为它们被视为文本文件。

这是git log的输出:

commit d075d282795362e03318d93c36406822facc015c (HEAD -> master)
Author: John Doe <john.doe@users.noreply.github.com>
Date:   Tue Mar 26 17:12:16 2019 +0100

    Bad state
    Gitattributed file added, PNG files are treated as text, they are now corrupted

commit fcaa5a87eb816ddafbd256e83ea4be004a87a6e8
Author: John Doe <john.doe@users.noreply.github.com>
Date:   Tue Mar 26 17:11:36 2019 +0100

    Good state
    PNG Files are treated as binary, they are not corrupted yet

首先将所有PNG文件重置为其初始状态:

git reset fcaa5a87eb816ddafbd256e83ea4be004a87a6e8 -- *.png

然后提交更改而不添加任何文件:

git commit -m 'Fix PNG files'

丢弃工作目录中的所有更改:

git checkout '*.png'

最后删除错误的.gitattributes条目或将其替换为:

*.png binary

您还可以使用gitattributes template,包括许多其他文件类型。


更新:

如果没有“良好”状态(图像完整无缺),则可以尝试通过处理文件来解决此问题。您需要添加缺少的换行符。您不知道正确的位置,因为git已将其全部删除。根据我的经验,如果仅在第一行的末尾添加一个回车符,它将修复大多数小的PNG文件。我不知道为什么,也无法保证,但是您仍然可以尝试:

首先删除所有PNG文件:

rm -f *.png

然后在.gitattributes中将PNG文件声明为二进制文件:

*.png binary

还原文件:

git checkout '*.png'

在第一行末尾添加回车符:

perl -i -p -e 's/$/$1\r/ if $. == 1;' *.png

答案 1 :(得分:2)

TL; DR

对于小文件,这很容易,对于60-200KB范围的文件,它仍然应该是可行的;对于大文件,这是没有希望的。

零或一个随机的换行符已损坏

容易。

此暴力打击脚本基于@Deniz在其答案中提供的Perl单行代码构建,它处理的文件仅丢失了一个随机换行符,而该换行符仅次于幻数:

lines=`wc -l < image.corrupted.png`
for x in `seq 1 $((lines+1))`; do 
   echo -n $x ''
   perl -pe 's/$/$1\r/ if ($. == 1 || $. =='$x')' < image.corrupted.png > image.fixed.png
   if pngcheck image.fixed.png; then
      echo Valid file substituting newline numbers 1 and $x
      break
   fi
done

该文件的大小为97KB,耗时约11s。

两个随机换行符已损坏

要有耐心。

这应该在缺少两个随机换行符以及第一个换行符的情况下起作用:

lines=`wc -l < image.corrupted.png`
foundit=
for x in `seq 3 $((lines+1))`; do 
   date
   echo $x
   time for y in `seq 3 $((lines+1))`; do
      echo -n $y ''
      perl -pe 's/$/$1\r/ if ($. == 1 || $. =='$x' || $. =='$y')' < image.corrupted.png > image.fixed.png
      if pngcheck image.fixed.png; then
         echo Valid file substituting newline numbers 1, $x and $y
         foundit=1
         break
      fi
   done
   if [[ $foundit ]]; then
      break
   fi
done

完成内循环的一次迭代需要2分钟,而花了一天半的时间才能找到固定图像。

如果文件小于200 KB,那么您可能会对这种方法抱有希望,如果您幸运的是损坏的随机换行符不超过2条,但是从3条随机换行符起就没有希望了。请记住,您期望每64 KB平均有一个随机损坏的换行符。因此,当然,如果您不走运,即使是较小的文件也可能会有更多CRLF。

三个或更多随机换行符损坏

就算了!

我正在播放一个464 KB的文件,除了第1行上的那个(用魔法数字),我知道3个随机的换行已损坏(比偶然的少,我想我很幸运)。 ),而我估计,要用蛮力方法找到正确的组合将需要4年的时间。我没事!

在这种情况下,我正在使用该暴力循环的3深版本。我打算让它运行好几天,但是我不希望它找到任何东西,因为我不愿意让它运行4年...

背景

上面的脚本基于以下假设:

标题

PNG文件具有一个神奇的数字-8字节的标头-其中包含两条换行符,一条以Dos风格的CRLF格式,另一条以Unix风格的LF。这些都是为了检测换行转换中的损坏而存在。因此,修复文件将需要修复幻数,例如,使用@Deniz在其答案中提供的解决方案。

参考:https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header

身体

PNG文件的主体已压缩,因此可以期望其中的字节和字节对具有较高的熵随机分布,例如均匀分布。 (毕竟,这就是压缩算法要努力实现的目标!)因此,我们可以预期平均每256个字节1个换行符,而平均256个字节中就有1个换行符是CRLF。因此,我们平均每64KB PNG文件将一个LF转换回CRLF。

pngcheck

程序pngcheck(我敢肯定可以使用它)来验证PNG文件的有效性,包括其幻数和存储在文件中的校验和。这样我们就可以知道何时发现哪些LF最初是CRLF。

“正确”的解决方案

一个很好的解决方案将利用数据格式的进一步知识,并为每个换行符做出明智的决定。例如,假设换行符最初分别是LF或CRLF,则可以考虑在每个换行符之后再考虑几十个字节而得到的两个解压缩的数据流。有了对数据格式的深入了解,或者可能是一些机器学习,这应该是可能的...

蛮力解决方案

由于对PNG文件格式缺乏深入的了解,因此可以通过蛮力恢复小文件,尝试将最多两个随机损坏的换行符转换回CRLF的所有组合。但是,原始文件中CRLF的数量使计算成本成指数增长,因此将方法推广到两个损坏的随机换行符之外是没有意义的。