我有一个现有的存储库,其中包含混合编码的文件-有些文件使用UTF-8,有些使用ANSI(例如Windows-1252)。大部分情况下一切正常,除了在ANSI文件上执行差异时我已经厌倦了看到“无效字符”,而且令我特别恼火的是,我无法使用我的GUI工具来对这些字符进行暂存或取消暂存。我正在寻找一种说服Git的方法,即某个文件使用非UTF-8编码,以便Git首先执行转换,然后对此进行魔术处理。
据我所知,有两种实现结果的方法:
[diff "win1252"]
textconv = "iconv -f windows-1252 -t utf-8"
.gitattributes
中,将文件标记为二进制文件并请求使用此过滤器将其转换为文本: *.txt diff=win1252
此方法似乎在孤立的git diff
中可以很好地工作,但是我遇到了几个我不知道如何解决的问题:
core.autocrlf = true
,该方法也不会在转换命令的输出上执行CRLF转换,因此我的差异将显示更改后的行的行尾差异。我可以创建一个脚本,该脚本将运行iconv来执行编码转换,然后将输出传递给dos2unix来执行EOL转换,但是似乎比较笨拙。git add -p
显示垃圾(甚至比“未知字符”还要糟糕),并且SourceTree停止分段并显示一条错误消息,即找不到原始文本。虽然我可能能够学习与#1和#2一起生活,但#3是一个阻塞问题,因为我主要需要进行此转换以促进带有“未知字符”的帅哥的演出。我当前的工作流程使用git add -p
而不进行任何转换,可能会显示“未知字符”,但至少可以正常工作。
GUI的更改不切实际:我尝试过的所有其他GUI都比这严重得多。
.gitattributes
中,将文件标记为具有自定义编码的文本文件: *.txt text working-tree-encoding=windows-1252
据我所知,这种方法涵盖了上面列出的所有抱怨,并且在命令行和GUI中都可以正常工作。不幸的是,有一个主要警告:它仅适用于在设置了该属性后created的文件。对于在添加此属性之前创建的文件,Git将为每个包含这些未编码字符的文件显示更改(从“未知字符”到Windows-1252)。另外,克隆存储库后,它会抱怨它“未能将'a.txt'从UTF-8编码到Windows-1252”。看来文件实际上是正确克隆的(与原始字节逐字节匹配),但仍然显示出差异。基本上,我将不得不使用“未知字符”提交每个文件,以将其重新编码为存储库中的UTF-8,这将使我的历史陷入困境,并使Blame无法使用。
似乎可行的方法可能是使用类似git filter-branch
的方法,但是对于整个存储库(是否有类似的方法?),将所有现有文件转换为UTF-8 并且将属性添加到第一次提交,但我担心要做这么大的事情。另外,我希望我会丢失以前的提交ID,这是不幸的(我在可执行文件上标记了提交ID,以便轻松地定位其生成版本)。
是否有任何方法可以克服所描述方法的缺点,或者是否有另一种方法不易受其影响?
通过使用working-tree-encoding
,您处在正确的轨道上,但还需要再执行一步。
在创建.gitattributes
文件的同一提交中,运行git add --renormalize .
,它将获取所有工作树文件并根据指定的编码对其进行过滤。然后,您要在同一次提交中提交所有更改的文件和.gitattributes
文件,然后将它们以UTF-8的形式存储在存储库中,但在您的工作树中为Windows-1252。
这确实有一个缺点,即git blame
必须跳回该提交之外,但是您可以指定--ignore-rev
或--ignore-revs-file
(或配置选项blame.ignoreRevsFile
)忽略该修订,一切都会正常进行。