前言
本篇是上篇文章—— 记一次曲折的多资源文件拆分折腾过程(1) 的续篇。在上篇文章找到了导致编译报错的根本原因是 .rc
文件的编码不再是默认的 UTF-16LE-BOM
了。但是为什么 .rc
文件的编码会发生变化,并没有深究。本文继续探究一下。
git 导致了文件编码变化?
经过一系列的确认,确定是执行 git restore .
(与 git checkout .
等价)的时候导致 .rc
文件的编码发生了变化。难道是 git
的 bug
?
仔细回想,在设置 .gitattributes
之前一切正常,设置 .gitattributes
之后,就出问题了。为了进一步打消疑虑,我特意删除了 .gitattributes
,然后再执行 git restore .
,发现一切恢复正常了。
看来,.gitattributes
的设置是导致 .rc
文件编码发生变化的罪魁祸首。
为什么要设置 .gitattributes
呢?在上一篇文章中提到了,为了不让 git
把 .rc
和 .rc2
文件当成二进制文件来管理,在 .gitattributes
中把 .rc
和 .rc2
的 working-tree-encoding
设置成了 UTF-16
。为什么我要把 .rc
和 .rc2
的 working-tree-encoding
设置成 UTF-16
呢?
回顾
在设置之前我是查看了 .gitattributes
的官方文档 的。文档中说,如果文件编码是 UTF-16 with BOM
的话,可以设置 working-tree-encoding
为 UTF-16
,如果文件编码是 UTF-16 little endian without BOM
,可以设置 working-tree-encoding
为 UTF-16LE
。相关描述截图如下:
我的注意力被红框高亮的部分吸引了,于是就在 .gitattributes
里做了如下设置。
但是,当我使用 git add .
添加文件到暂存区的时候,报了如下错误:
提示推荐使用 UTF-16
。而且,在 pitfalls
的介绍里,也说 .rc
和 .ps1
有时候会按 UTF-16
编码。描述截图如下:
于是,我就乖乖地按照提示把 UTF16-LE
改成了 UTF-16
。改完之后,果然不报错了。于是,我就掉坑里了,废了好大劲儿才爬出来。
再看文档
再次查看文档,细细的读了一遍关于 working-tree-encoding
的介绍。看到了下面这行至关重要的描述:
use
UTF-16LE-BOM
instead ofUTF-16LE
if you want UTF-16 little endian with BOM.
就在给出的两个例子中间,如下图:
也就是说如果文件是 UTF-16 little endian with BOM
编码的话,working-tree-encoding
要设置为 UTF-16LE-BOM
。
一般,.rc
文件是 UTF-16 little endian with BOM
的(折腾完之后才深刻意识到这一点的)。
Bonus
通过 working-tree-encoding
设置文件的编码来避免 git
把文件当成二进制的做法,并不是完美的。具体可以参考官方文档中的描述,如下图:
大体意思是:
git
会把 ASCII
编码,包括其它一些编码(例如,UTF-8,ISO-8859-1,...
)的文件当成文本格式的文件对待,会把另外一些编码(例如,UTF-16
) 的文件当成二进制格式的文件对待。
如果某些文件设置了 working-tree-encoding
,那么在存储到 git
内部的时候,会转换成 UTF-8
格式。当签出的时候,再从 UTF-8
转换成原来的格式。
working-tree-encoding
是有一些缺陷的:
- 一些
git
实现不支持working-tree-encoding
,如果有同事使用支持working-tree-encoding
的客户端,另外一些同事使用的是不支持working-tree-encoding
的客户端,那么容易出问题。 - 一些字符集在与
UTF-8
编码来回转换的时候有问题 (not UTF-8 round trip safe
),比如,SHIFT-JIS
字符集就有这方面的问题。 - 整个编码转换的过程中可能导致某些操作变慢(比如,
git checkout, git add
)。
只有当文件不能存储成 UTF-8
格式并且希望 git
把这个文件当成文本文件的时候才使用 working-tree-encoding
。
总结
- 在设置
.gitattributes
中的working-tree-encoding
之前,强烈建议仔细阅读官方文档!而且一定一定要仔细! - 设置过
working-tree-encoding
的文件,在git
内部会以UTF-8
格式存储,签出的时候再转换回指定的编码。 - 一般情况下,
.rc
文件的编码是UTF-16 Little Endian with BOM
,所以正确的working-tree-encoding
是UTF-16LE-BOM
。 - 简单总结了一张
working-tree-encoding
与文件编码的对照表,如下:
working-tree-encoding | 对应的文件编码 |
---|---|
UTF-16LE | UTF-16 Little Endian (No BOM) |
UTF-16BE | UTF-16 Big Endian (No BOM) |
UTF-16LE-BOM | UTF-16 Little Endian (With BOM) |
UTF-16BE-BOM | UTF-16 Big Endian (With BOM) |
UTF-16 | UTF-16 Big Endian (With BOM) |
参考资料
https://www.git-scm.com/docs/gitattributes
未完待续
至此,在本次折腾过程中遇到的所有问题都已经清楚了。但是这个问题“坑”我太深了,于是我又翻看了 git
源码,由于相关内容有点多,把参考源码的过程记录在了下一篇文章中,敬请期待。