1

记一次曲折的多资源文件拆分折腾过程(2)

 2 years ago
source link: https://bianchengnan.gitee.io/articles/using-multiple-rc-and-stop-git-treating-rc-as-binary-part2-findout-why-rc-encoding-changed/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本篇是上篇文章—— 记一次曲折的多资源文件拆分折腾过程(1) 的续篇。在上篇文章找到了导致编译报错的根本原因是 .rc 文件的编码不再是默认的 UTF-16LE-BOM 了。但是为什么 .rc 文件的编码会发生变化,并没有深究。本文继续探究一下。

git 导致了文件编码变化?

经过一系列的确认,确定是执行 git restore . (与 git checkout . 等价)的时候导致 .rc 文件的编码发生了变化。难道是 gitbug

仔细回想,在设置 .gitattributes 之前一切正常,设置 .gitattributes 之后,就出问题了。为了进一步打消疑虑,我特意删除了 .gitattributes,然后再执行 git restore .,发现一切恢复正常了。

看来,.gitattributes 的设置是导致 .rc 文件编码发生变化的罪魁祸首。

为什么要设置 .gitattributes 呢?在上一篇文章中提到了,为了不让 git.rc.rc2 文件当成二进制文件来管理,在 .gitattributes 中把 .rc.rc2working-tree-encoding 设置成了 UTF-16。为什么我要把 .rc.rc2working-tree-encoding 设置成 UTF-16 呢?

在设置之前我是查看了 .gitattributes官方文档 的。文档中说,如果文件编码是 UTF-16 with BOM 的话,可以设置 working-tree-encodingUTF-16,如果文件编码是 UTF-16 little endian without BOM,可以设置 working-tree-encodingUTF-16LE。相关描述截图如下:

gitattributes-utf16-utf16-le

我的注意力被红框高亮的部分吸引了,于是就在 .gitattributes 里做了如下设置。

set-rc-as-utf-16le-in-gitattributes

但是,当我使用 git add . 添加文件到暂存区的时候,报了如下错误:

git-add-warning-and-fail

提示推荐使用 UTF-16。而且,在 pitfalls 的介绍里,也说 .rc.ps1 有时候会按 UTF-16 编码。描述截图如下:

rc-is-documented-as-utf-16

于是,我就乖乖地按照提示把 UTF16-LE 改成了 UTF-16。改完之后,果然不报错了。于是,我就掉坑里了,废了好大劲儿才爬出来。

再次查看文档,细细的读了一遍关于 working-tree-encoding 的介绍。看到了下面这行至关重要的描述:

use UTF-16LE-BOM instead of UTF-16LE if you want UTF-16 little endian with BOM.

就在给出的两个例子中间,如下图:

gitattributes-utf16-utf16-le

也就是说如果文件是 UTF-16 little endian with BOM 编码的话,working-tree-encoding 要设置为 UTF-16LE-BOM

一般,.rc 文件是 UTF-16 little endian with BOM 的(折腾完之后才深刻意识到这一点的)。

Bonus

通过 working-tree-encoding 设置文件的编码来避免 git 把文件当成二进制的做法,并不是完美的。具体可以参考官方文档中的描述,如下图:

working-tree-encoding-pitfalls

大体意思是:

git 会把 ASCII 编码,包括其它一些编码(例如,UTF-8,ISO-8859-1,...)的文件当成文本格式的文件对待,会把另外一些编码(例如,UTF-16) 的文件当成二进制格式的文件对待。

如果某些文件设置了 working-tree-encoding,那么在存储到 git 内部的时候,会转换成 UTF-8 格式。当签出的时候,再从 UTF-8 转换成原来的格式。

working-tree-encoding 是有一些缺陷的:

  1. 一些 git 实现不支持 working-tree-encoding,如果有同事使用支持 working-tree-encoding 的客户端,另外一些同事使用的是不支持 working-tree-encoding 的客户端,那么容易出问题。
  2. 一些字符集在与 UTF-8 编码来回转换的时候有问题 (not UTF-8 round trip safe),比如, SHIFT-JIS 字符集就有这方面的问题。
  3. 整个编码转换的过程中可能导致某些操作变慢(比如,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-encodingUTF-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 源码,由于相关内容有点多,把参考源码的过程记录在了下一篇文章中,敬请期待。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK