如何通过不正确的.gitattributes恢复损坏的PNG文件?

问题描述 投票:1回答:2

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

* text
# no settings for PNG files

PNG文件被git视为文本文件。现在我不能打开它们了,我也丢失了它们的原始副本。有没有办法恢复它们?谢谢!


更新:添加PNG文件时,.gitattributes已经在回购中。这意味着我无法在提交历史记录中找到PNG文件的良好状态。所有提交都是在Windows上完成的。

git png gitattributes
2个回答
3
投票

让我们来看一个你有2次提交的场景:

  • 在第一个中,所有PNG文件都以二进制形式处理,文件是合理的。
  • 第二次提交包括.gitattributes文件,所有PNG文件都被破坏,因为它们被视为文本文件。

这是git log输出:

commit d075d282795362e03318d93c36406822facc015c (HEAD -> master)
Author: John Doe <[email protected]>
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 <[email protected]>
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


2
投票

TL; DR

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

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

随和。

这个强力bash脚本建立在@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的文件我正在玩,在那里我知道3个随机换行已经损坏(偶然的机会少于预期,我想我很幸运),除了第1行(幻数)中的那个,以及我的估计是,用蛮力方法找到正确的组合需要4年时间。我没经营!

在这种情况下,我正在运行该暴力循环的3深版本。我会让它运行几天以获得它的乐趣,但我不希望它能找到任何东西,因为我不愿意让它运行4年......

背景

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

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

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

身体

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

pngcheck

程序pngcheck(我确定其中之一)可用于验证PNG文件的有效性,包括其幻数和存储在文件中的校验和。所以我们可以用来知道什么时候我们发现哪些LF最初是CRLF。

“正确”的解决方案

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

蛮力解决方案

由于缺乏对PNG文件格式的深刻理解,人们可以通过强力恢复小文件,尝试将最多两个随机损坏的换行符转换回CRLF的所有组合。但是,计算成本是原始文件中CRLF数量的指数,因此将方法概括为超出两个损坏的随机换行是毫无意义的。

© www.soinside.com 2019 - 2024. All rights reserved.