24

免责声明:通过 Git,我的意思是“我”搞砸了。

早些时候,我想git-gui向我展示diff认为是二进制文件的文件。

所以我对我的.\.gitattributes

*.ini       text
*.inc       text

但它没有用。 然后我对我的.\.git\info\attributes

*.ini       text
*.inc       text
*.inc crlf diff
*.ini crlf diff

它奏效了。

但是现在当我回到以前的提交时,它搞砸了......

中国文字应该是这样的: 英文字符

它不会发生在所有文件中。编辑:它只发生在其中包含任何特殊字符的文件中。

问:是提交本身的问题还是只是某些设置的问题?
问:我可以恢复吗?

4

4 回答 4

26

您的 ini 文件保存在 UTF-16LE 中,Windows 错误地将这种编码描述为“Unicode”。

Git 的默认差异工具不适用于 UTF-16,因为它不是与 ASCII 兼容的编码。这就是 git 最初将文件检测为二进制文件的原因。

LF/CRLF 换行符转换将每个 0x0A 字节视为换行符,并将其替换为 0x0D-0x0A。但是,在 UTF-16LE 文件中,换行符实际上是由 0x0A-0x00 表示的,用 0x0D-0x0A-0x00 替换它意味着你有奇数个字节,所以每个两字节代码单元的对齐在下一行是不同步的。因此,每隔一条线都会被破坏。

您的选择是:

  1. 恢复属性更改并让 Git 将文件作为二进制文件处理(失去差异的好处)。

  2. 以兼容 ASCII 的编码保存文件。看起来您的内容实际上没有任何非 ASCII 字符,所以希望这不是问题?通常,您希望将所有文件保存为 UTF-8 - 这是与 ASCII 兼容的,但也允许使用所有 Unicode 字符。但这取决于 Rainmeter 是否支持读取这样编码的 INI 文件(可能不支持)。

  3. 配置 git 以使用不同的 diff 工具,尽管这会使其他人使用您的 repo 变得更加复杂。

于 2013-07-08T09:09:26.337 回答
8

我最近遇到了类似的问题。我们.gitattributes在根级别有一个项目范围的文件,其中包括以下行:-

* text=auto
*.sql     text

我们的一个团队正在使用 SQL Management Studio 编写 SQL 代码,他不知道该代码将文件保存为 UTF-16。他能够毫无问题地将代码签入 Git,但在签出时,代码被翻译成本文所述的中文字符。

相关文件的 hexdump 确认问题确实是 0x000A 到 0x000A0D 的转换。

对我们来说,解决方案是使用以下方法将文件转换为 ASCII:-

  1. 从工作目录中删除有问题的文件
  2. 在本地目录中创建一个临时.gitattributes文件,强制 git 签出文件而不进行行尾转换。例如包括该行*.sql binary

  3. 从 Git 签出文件。您应该看到文件没有被翻译并且没有中文字符。

  4. 将文件转换为 ASCII。我们为此使用了 Notepad++,但也可以使用iconv作为 Git For Windows 的一部分安装的 . 如果文件包含非 ASCII 字符,我认为 UTF-8 也是一种选择——但这对于我们的目的来说不是必需的。
  5. 签入文件的 ASCII 版本
  6. 删除本地.gitattributes文件
于 2016-05-09T15:45:07.620 回答
2

这是一个(坏的)power-shell脚本,它将修复处于这种状态的文件。它将用“0x0D 0x00 0x0A”替换序列“0x0D 0x00 0x0D 0x0A”,然后覆盖给出的文件。

之后,您可能应该将文件重新保存为 UTF-8 之类的文件。

function Fix-Encoding
{
    Param(
        [String]$file
    )
    $f = get-item $file;
    $bytes = [System.IO.File]::ReadAllBytes($f.fullname);
    $output = new-object "System.Collections.Generic.List[System.Byte]"
    $output.Capacity = $bytes.Length

    for ($i = 0; $i -lt $bytes.Length; $i++)
    { 
        if ($i -lt $bytes.Length + 3)
        {
            if ($bytes[$i] -eq 0x0D -and $bytes[$i+1] -eq 0x00 -and $bytes[$i+2] -eq 0x0D -and $bytes[$i+3] -eq 0x0A) 
            {
                $output.Add(0x0D);
                $output.Add(0x00);
                $output.Add(0x0A);
                $i += 3
            }
            else {
                $output.Add($bytes[$i]);
            }
        }
     }
    [System.IO.File]::WriteAllBytes($f.fullname, $output)
}
于 2018-06-22T23:19:35.913 回答
0

补充@bobince 的一个很好的解释。此问题的一种解决方案(带有特殊字符的文件除外)是将所有内容转换为 utf-8。我通过在目录中的所有文件(从没有弄乱文件的计算机)上运行记事本++中的python脚本解决了这个问题。

我在这里找到了原始脚本

notepad++ python 脚本的副本:

import os;
import sys;
filePathSrc="C:\\Temp\\UTF8"
for root, dirs, files in os.walk(filePathSrc):
    for fn in files:
      if fn[-4:] != '.jar' and fn[-5:] != '.ear' and fn[-4:] != '.gif' and fn[-4:] != '.jpg' and fn[-5:] != '.jpeg' and fn[-4:] != '.xls' and fn[-4:] != '.GIF' and fn[-4:] != '.JPG' and fn[-5:] != '.JPEG' and fn[-4:] != '.XLS' and fn[-4:] != '.PNG' and fn[-4:] != '.png' and fn[-4:] != '.cab' and fn[-4:] != '.CAB' and fn[-4:] != '.ico':
        notepad.open(root + "\\" + fn)
        console.write(root + "\\" + fn + "\r\n")
        notepad.runMenuCommand("Encoding", "Convert to UTF-8 without BOM")
        notepad.save()
        notepad.close()
于 2017-06-01T20:54:54.150 回答