在Mercurial on Unicode文件(MS Windows)中获取可读的差异显示
我正在尝试将一些Windows PowerShell脚本存储在Mercurial存储库中。PowerShell编辑器似乎喜欢将文件保存为UTF-16 Unicode。这意味着有大量的在Mercurial on Unicode文件(MS Windows)中获取可读的差异显示,windows,unicode,mercurial,diff,tortoisehg,Windows,Unicode,Mercurial,Diff,Tortoisehg,我正在尝试将一些Windows PowerShell脚本存储在Mercurial存储库中。PowerShell编辑器似乎喜欢将文件保存为UTF-16 Unicode。这意味着有大量的\0字节,Mercurial使用这些字节来区分“文本”和“二进制”文件。我知道这对Mercurial存储数据的方式没有影响,但这确实意味着它显示二进制差异,这有点难以读取。有没有办法告诉Mercurial这些确实是文本文件?大概我需要说服Mercurial为特定的文件类型使用支持Unicode的外部diff程序。我已
\0
字节,Mercurial使用这些字节来区分“文本”和“二进制”文件。我知道这对Mercurial存储数据的方式没有影响,但这确实意味着它显示二进制差异,这有点难以读取。有没有办法告诉Mercurial这些确实是文本文件?大概我需要说服Mercurial为特定的文件类型使用支持Unicode的外部diff程序。我已经解决了这个问题,使用NotePad++创建了一个新文件,并将其保存为PowerShell文件(.ps1扩展名)。NotePad++将创建一个纯文本ANSI文件。创建后,我可以在PowerShell编辑器中打开文件,并根据需要进行任何更改,而无需编辑器修改文件编码
免责声明:我刚才遇到了这个问题,所以我不确定是否有任何影响,但到目前为止,我的脚本似乎正常工作,我的差异显示得很好。这可能与您无关;如果最后一段听起来不像,请阅读
我不确定这是否是您所需要的,但我需要的是UTF-16LE内容的差异,而不仅仅是“二进制文件不同”——几个月前,当我四处搜索时,我发现一个线程和bug正在讨论它。我现在找不到这个迷你扩展的原始源代码(尽管它正在做那个补丁所做的),但我得到的是一个扩展,BOM.py
:
#!/usr/bin/env python
from mercurial import hg, util
import codecs
boms = [
codecs.BOM_UTF8,
codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE,
codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE
]
def binary(s):
if s:
for bom in boms:
if s.startswith(bom):
return False
return '\0' in s
return False
def reposetup(ui, repo):
util.binary = binary
import codecs
from mercurial import mdiff
unidiff = mdiff.unidiff
def new_unidiff(a, ad, b, bd, fn1, fn2, r=None, opts=mdiff.defaultopts):
"""
A simple wrapper around mercurial.mdiff.unidiff which first decodes
UTF-16LE text.
"""
if a.startswith(codecs.BOM_UTF16_LE):
try:
# Gets reencoded as utf-8 to be a str rather than a unicode; some
# extensions may expect a str and may break if it's wrong.
a = a.decode('utf-16le').encode('utf-8')
except UnicodeDecodeError:
pass
if b.startswith(codecs.BOM_UTF16_LE):
try:
b = b.decode('utf-16le').encode('utf-8')
except UnicodeDecodeError:
pass
return unidiff(a, ad, b, bd, fn1, fn2, r, opts)
mdiff.unidiff = new_unidiff
这会加载到.hgrc(或您的用户\username\mercurial.ini)中,如下所示:
[extensions]
bom = ~/.hgexts/BOM.py
注意:路径在Windows和Linux之间会有所不同;在我的Windows copy上,我将路径设置为\…\which
(它位于USB磁盘上,驱动器号可以在其中更改)。不幸的是,相对路径是相对于当前工作目录而不是存储库根目录或任何类似的内容获取的,但是如果您要将其保存在C:drive上,您可以只放置完整路径
在Linux(我的主要开发环境)中,这工作得很好;在命令提示符(我仍然经常使用)中,它通常运行良好。我从未在PowerShell中尝试过,但我希望它比命令提示符更好地支持命令行中的任意空字节
我不确定这是否是你想要的;顺便说一句,你说的是“二进制差异”,我怀疑你可能已经有了这个,或者正在做hg diff-a
,这也实现了同样的目标。在这种情况下,我所能想到的就是编写另一个扩展,它接受UTF-16LE并尝试将其解码为UTF-8。我不确定这种扩展的语法,但我可能会尝试一下
Edit:现在通过commands.py、cmdutil.py、patch.py和mdiff.py搜索mercurial源代码,我看到二进制差异是用base85编码(patch.b85diff)而不是普通的差异来完成的。我没有意识到这一点,我认为这只是强迫它进行差异。在这种情况下,或许这一文本毕竟是相关的。我在等待答复,看看是不是真的 如果我的另一个答案不符合你的要求,我想这一个可能会;虽然我还没有在Windows上测试过它,但它在Linux上运行良好。它用一个新函数包装
mercurial.mdiff.unidiff
,将utf-16le转换为utf-8,这可能是一件令人讨厌的事情。这不会影响hg st
,但会影响hg diff
。一个潜在的陷阱是BOM也将从UTF-16LE BOM更改为UTF-8 BOM
不管怎样,我想它可能对你有用,所以在这里
扩展文件utf16decodediff.py
:
#!/usr/bin/env python
from mercurial import hg, util
import codecs
boms = [
codecs.BOM_UTF8,
codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE,
codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE
]
def binary(s):
if s:
for bom in boms:
if s.startswith(bom):
return False
return '\0' in s
return False
def reposetup(ui, repo):
util.binary = binary
import codecs
from mercurial import mdiff
unidiff = mdiff.unidiff
def new_unidiff(a, ad, b, bd, fn1, fn2, r=None, opts=mdiff.defaultopts):
"""
A simple wrapper around mercurial.mdiff.unidiff which first decodes
UTF-16LE text.
"""
if a.startswith(codecs.BOM_UTF16_LE):
try:
# Gets reencoded as utf-8 to be a str rather than a unicode; some
# extensions may expect a str and may break if it's wrong.
a = a.decode('utf-16le').encode('utf-8')
except UnicodeDecodeError:
pass
if b.startswith(codecs.BOM_UTF16_LE):
try:
b = b.decode('utf-16le').encode('utf-8')
except UnicodeDecodeError:
pass
return unidiff(a, ad, b, bd, fn1, fn2, r, opts)
mdiff.unidiff = new_unidiff
在.hgrc
中:
[extensions]
utf16decodediff = ~/.hgexts/utf16decodediff.py
(或等效路径。)具体来说,我的问题是使用OrtoiseHG的“提交”工具中的“文本差异”页面,该页面通常显示所选文件中更改的良好摘要,但显示UTF-16文件中的垃圾。@orad:截至2010年9月22日,我仍然没有找到答案。BOM.py答案将起作用。只需将整个内容复制到一个文件中,然后编辑(或创建)您的users\yourname\Mercurial.ini文件,并在“[extensions]”行下添加一行(如果没有这样的行),添加一行name=file(如“bom=C:\path\to\the\bom.py”)。小心!虽然此扩展适用于命令行上的差异化,但我在通过
qnew
创建MQ修补程序时遇到了损坏问题。转换为UTF-8也适用于Xcode中的.strings文件(默认情况下genstrings生成UTF-16LE)。不幸的是,这种方法存在内存问题:文件被阻塞(通过mercurial,而不是此扩展)因此,如果内存紧张,您可能会耗尽。它要求您设置--config diff.nobinary=True
(根据个人经验,我知道这将破坏mq修补程序,因此我不建议永久启用它)以到达包装器。如果isinstance(a,str),我还建议使用:
和如果isinstance(b,str)
因为当执行一个版本缺少文件而另一个版本具有这些变量的差异时,可能是非类型的,并导致扩展崩溃mercurial