为什么Git认为我的.sql文件是二进制文件?

108

我有一些.sql文件,这是我第一次将它们推送到Github上。但是当我查看提交记录时,它显示:

BIN  WebRole/Sql/Database.sql View
Binary file not shown

有人能告诉我为什么它显示“未显示二进制文件”吗?


可能是重复的问题:为什么Git认为我的cs文件是二进制文件? - Nick Grealy
7个回答

116

仅仅通过扩展名不能让GitHub识别它是否是文本文件。
因此,必须查看它的内容。

正如在“为什么Git将这个文本文件视为二进制文件?”中提到的那样,它的内容可能不包含足够的ASCII字符来猜测它是文本文件。

您可以使用.gitattributes文件明确指定一个.sql应该是文本而不是二进制文件。

*.sql diff

更新于2018年:正如我在“Utf-8编码在utf-8编码的文档中不起作用”中提到的,Git 2.18 .gitattributes有一个新的working-tree-encoding属性。
所以,如Rusi答案所示:

*.sql text working-tree-encoding=UTF-16LE eol=CRLF

正如kostix评论中所述:

如果这些文件是由Microsoft SQL管理工具(或您正在使用的某个版本的MS SQL Server管理工具)生成的,则它保存的文件编码为UCS-2(或UTF-16)-一种双字节编码,在Git眼中确实不属于文本。

您可以在"Git says “Binary files a… and b… differ” on for *.reg files"中看到一个例子

正如在"Set file as non-binary in git"中所提到的:

为什么Git将我的文件标记为二进制文件?答案是因为它在文件的前8000个字符中的某个位置看到了NUL(0)字节。通常,这是因为该文件被保存为除UTF-8之外的其他格式。因此,它可能以UCS-2、UCS-4、UTF-16或UTF-32的形式保存。在使用ASCII字符时,所有这些字符都有嵌入的NUL字符。


正如Neo评论中所提到的(以及Why does Git treat this text file as a binary file?):

您可以通过从“文件”菜单中的“高级保存选项”菜单项中选择编码“带签名的UTF-8”来更改保存文件的编码为UTF-8。


20
如果这些文件是由Microsoft SQL Management Studio(或您使用的MS SQL Server管理工具版本中称之为的任何名称)生成的,那么它保存的文件将以UCS-2(或UTF-16)编码--这是一种双字节编码,Git认为它不是文本。请注意,翻译后的内容保留了原来的意思,且没有解释和额外的信息。 - kostix
19
在SSMS中,您可以通过在“文件”菜单中选择“高级保存选项”菜单项并选择编码为“带签名的UTF-8”的方式来更改已保存文件的编码方式。来源:https://dev59.com/E2w15IYBdhLWcg3wD3hk#21170043 - Neo
2
@Neo 好观点。我已经将你的评论包含在答案中以增加可见性。 - VonC
7
如果你在Windows上运行Git Bash并且不想覆盖对文件所做的任何更改,可以尝试另一个巧妙的方法:只需输入“dos2unix *.sql”。这将把所有UCS2文件转换为UTF8,使得git能够识别文本。 - Slothario
1
@thebfactor请检查dos2unix命令的选项“iso”,看看是否有帮助:https://www.computerhope.com/unix/dos2unix.htm - VonC
显示剩余5条评论

18
自Git版本2.18起,有一个名为working-tree-encoding的选项,专门用于这些情况。请参阅gitattributes文档。
[确保你的Git版本(以及所有使用该仓库的人)至少与2.18相同] 找出SQL文件的编码格式,例如使用file命令。 如果(假设)它在Windows机器上是utf-16无BOM,则将其添加到您的gitattributes文件中。
*.sql text working-tree-encoding=UTF-16LE eol=CRLF

如果是UTF-16小端序(带BOM),则进行处理。

*.sql text working-tree-encoding=UTF-16 eol=CRLF

有趣的部分在于如果你有一个良好的ASCII、Windows-1252和UTF-16混合的组合。有趣的是,Git并不使用file命令,或者与file命令相同的逻辑来猜测编码,当你指定text时。我推测Git开发人员不想开始猜测编码的兔子洞。除非在gitattributes中指定text时,Git确实使用类似于file的逻辑。如果你指定了working-tree-encoding=UTF-16LE且你的一些SQL文件是Windows-1252编码,我认为你可能会遇到问题,因为Git会尝试将其转换为内部使用的UTF-8编码。 - Jason S
@JasonS 我不确定你在说什么。我猜你是在混淆行尾符和文件编码(这个问题)。你应该将这两个属性视为正交的。 - Rusi
不,我说的是编码,而不是行尾。假设你有多个开发人员在Windows上为SQL Server编写SQL代码,并且对于所有的SQL文件,你的gitattributes设置为working-tree-encoding=UTF-16,但其中一个开发人员将文件保存为Windows-1252甚至ASCII编码。Git会认为这个文件是UTF-16编码,试图将其转换为UTF-8(用于内部使用),并且可能会根据Windows-1252或ASCII编码文件的内容而失败。我还没有测试过这一点。 - Jason S
@JasonS 如果你将编码指定为X,并提供一个实际上是Y编码的文件,那么可以肯定文件会乱码。【未经测试,来自手册】你应该尊重你自己的.gitattributes!对于text来说就是另一回事:在Windows上可以且必须使用CRLF,在*nix上则使用LF。这是唯一使不同操作系统上的文件统一在git中的情况。 - Rusi

11

使用链接问题中被接受的答案以及其他一些评论,我想出了这个解决办法,它可以在Win10上运行且有效。

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem -Recurse *.sql | foreach {
    $MyPath = $_.FullName;
    $Contents = Get-Content $MyPath
    [System.IO.File]::WriteAllLines($MyPath, $Contents, $Utf8NoBomEncoding)
}

1
有趣。使用PowerShell,不错的选择。+1 - VonC
在我的情况下,Get-Content需要一个标志来处理文件名中的方括号(例如[dbo]):$Contents = Get-Content -LiteralPath $MyPath - Jeremy Murray

4
这是一个适用于我自己的快速解决方法,使用SSMS 2012。在“工具”=> “选项”=>“环境”=>“国际设置”下,如果将语言从“英语”更改为“与Microsoft Windows相同”(可能会提示您重新启动SSMS以使更改生效),则不再将UTF-16用作默认编码新建文件时,我创建的所有文件现在都有编码1252(文件=>高级保存选项),这是一种8位编码方案,并且似乎没有与Git Diff相关的问题。

4

如果你在SSMS 2008 R2中遇到了这个问题(是的,仍然存在!),你可以按照以下步骤设置默认编码:

  • 找到目录C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\SqlWorkbenchProjectItems\Sql

不同的位置可能有所不同。这是Windows 7 64位上默认安装使用的目录。

  • 在该位置下增加(或编辑)一个空的SQL文件SQLFile.sql。

这将作为新的.SQL文件的模板。使用你需要的编码保存它(在我的情况下,使用Windows-1252编码和Windows换行符)。'保存'按钮右侧的箭头给出了编码选择。

你需要与开发团队协调编码,以避免git和SSMS带来的麻烦。


2
我在C:\Program Files (x86)\Microsoft SQL Server\110\Tools\Binn\ManagementStudio\SqlWorkbenchProjectItems\Sql找到了适用于SSMS 2012的文件。 - Aaron D
1
以及SSMS2016:C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn\ManagementStudio\SqlWorkbenchProjectItems\Sql - Coxy

1
解决这个问题的方法是强制文件使用8位编码。您可以运行此PowerShell脚本来更改当前目录及其子目录中所有.SQL文件的编码。
Get-ChildItem -Recurse *.sql | foreach {
  $FileName = $_.FullName;
  [System.Io.File]::ReadAllText($FileName) | Out-File -FilePath $FileName -Encoding UTF8;
}

2
一个很好的策略,但是这对我没有移除BOM标记,而git将其视为二进制。相反,我使用了使用PowerShell在UTF-8中写入文件而不带BOM的答案,该答案使用[System.IO.File] :: WriteAllLines($MyPath, $MyFile, $Utf8NoBomEncoding) - KyleMit

0
我正在使用Microsoft SQL Server Management Studio 19.1的“生成脚本”向导从我的数据库导出SQL命令,并将生成的.sql文件提交到Github。
默认情况下,向导会将.sql文件写入“Unicode文本”。这导致Github认为该文件是二进制格式。
在我的情况下,简单的解决方法是在向导中将导出格式更改为“ANSI文本”,而不是“Unicode文本”在“另存为”选项中。现在,Github能够将该文件识别为纯文本,并提供内容的差异比较。
不需要PowerShell命令,也不需要运行后处理批处理文件。只需将文本导出为“ANSI”,Github就会很高兴。

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接