关于编码选择的问题

我不止一次被编码折磨了,我的情况如下:

我在 linux 虚拟机下使用 emacs,用 samba 将一个文件夹共享给 Windows。我在 linux 下的文件都是有版本控制的,使用 utf-8-unix 编码。

然后问题来了,我在 Windows 工作环境下所使用的一个程序只支持 chinese-gbk-dos 编码,否则中文会乱码(这个程序是工作必须,没有替代)。

如果使用 utf-8-unix 保存文件,那么 windows 下面中文乱码;如果用 chinese-gbk-dos 保存文件,行尾为 crlf,会在 git diff 时在行尾显示 ^M,这是我想尽量避免的。

有没有什么两全其美的办法呢?

专有软件?

不如用脚本自动转换编码。只要替换一下换行符就可以。

spacemacs/uxix2dos, spacemacs/dos2unix用这两个函数

(defun spacemacs/dos2unix ()
  "Converts the current buffer to UNIX file format."
  (interactive)
  (set-buffer-file-coding-system 'undecided-unix nil))

(defun spacemacs/unix2dos ()
  "Converts the current buffer to DOS file format."
  (interactive)
  (set-buffer-file-coding-system 'undecided-dos nil))

是的

有没有好的工作流?目前我想到两种方式:

一种方案是就用 gbk 编码,然后每次 commit 时都自动转成 utf-8,我个人不太喜欢这种工作流,因为编辑和最后提交的都不是同一个文件,心里感觉很不踏实 :joy:

另外一种方案是每次保存都另外生成一个 gbk 版本的文件用于在 windows 下面运行,这样做有两个弊端,一个是增加了维护的难度,另外从 Windows 对文件进行修改后,同步更改到另一个版本会比较麻烦。

我需要的不是手动转换,因为我要频繁在两种环境下切换,在 Linux 下编辑,在 Windows 下运行。

那给你的mode加个exit/save hook,记得判断下你的系统

我可能没有表述清楚,windows 下面用的是专有软件,不是 emacs。它类似于 IDE,主要用于运行,测试 Linux 下面写好的文件,偶尔编辑。Linux 下面用的才是 Emacs。

把这个函数加到magit-diff-mode-hook里面试试?

(defun ztlevi/hidden-dos-eol ()
  "Do not show ^M in files containing mixed UNIX and DOS line endings."
  (interactive)
  (setq buffer-display-table (make-display-table))
  (aset buffer-display-table ?\^M []))
1 个赞

这个问题是由于你在 linux/windows 修改了同一个副本

diff 的时候自然就检测到:Linux 下编辑产生的 LF,Windows 下编辑产生的 CRLF。

可以通过以下设置忽略:

$ git config core.whitespace cr-at-eol

在一个文件中同时存在 CRLF 和 LF 有点凌乱,最好统一起来。文件采用 chinese-gbk-dos 编码,然后 Linux 下的仓库设置:

$ git config core.autocrlf true

checkout 出来的文件就自动转 LF 结尾了,commit 自动转回 CRLF。

windows 另外克隆一份,用来跑专用程序和偶尔修改。

(我没有环境重现你的问题,以上方案来自过去的经验)

5 个赞

已收藏,跟老司机确实能学到不少东西 :smile:

这样做有一个缺点,就是 git diff 的时候中文显示乱码,有解决办法吗?

所以这也是为什么我一直坚持 utf-8 编码的原因——不会在意想不到的地方乱码。

因为我用 magit,git diff 乱码这个问题可能无解的:

看来还得用回 utf-8 编码啊,问题依旧。

我现在使用一种相对比较 hacky 的解决办法:

保存文件时,检查文件中是否含有 non-ascii 字符:
    - 如果有,另存一份 gbk 编码的副本,后缀为原来后缀前面加 .dos,比如 .dos.txt 这样的。

然后在 Windows 下面使用 dos 版本的文件,并且尽量不修改。 在 Linux 下面修改原始版本 (utf-8) 的文件,并做版本控制。

代码很简单,而且适用范围很窄,我就不放了。如果有感兴趣的同学可以留言,我再放出来。

在找到更好的解决方案之前,先用这种办法凑合一下。

magit 没用过不知道,git diff 还是有解的,(为了不影响其它项目)在当前 .git/config 中加入:

[diff "localizablestrings"]
    textconv = "iconv -f gbk -t utf-8"

然后项目根目录创建一个 .gitattributes 文件,内容为:

* diff=localizablestrings

可以只对特定文件,比如 *.txt

参考:http://blog.xk72.com/post/31456986659/diff-strings-files-in-git

3 个赞

我试试 magit 下可行不

Edit: 我是不是哪里做错了,diff 乱码倒是没有了,但是 ^M 也回来了:

甚至连 gitattributes 文件(utf-8)里也有。

@twlz0ne 你有碰到这种情况吗?

没用过 magit ╮(╯_╰)╭

不知道以下参数有没有效果:

User Option: magit-diff-hide-trailing-cr-characters

Whether to hide ^M characters at the end of a line in diffs.

1 个赞

正解!

我都不知道还有这个变量,这下解决了我的大问题,十分感谢!

我又来提问了,用这种方法,其它问题都解决了,然后一直用英文写 commit message 都没有问题。今天用中文写了 一次commit message,结果乱码又出现了。

图片

请问这个应该怎样解决? @twlz0ne

吐槽一下,版本控制时用 utf-8 之外的编码坑真多啊 :joy:

因为文件的内容是 gbk,而 commit 又是 utf-8?

magit 能不能分别设置编码?

好像不能。实在是让人困扰