Sukka's Blog

童话只美在真实却从不续写

Travis CI 使用 Windows 环境时换行符自动转换为 CRLF 的解决方案

Sukka's Avatar 2019-10-06 笔记本

  1. 1. TL; DR:
  2. 2. 缘起
  3. 3. 分析
  4. 4. 解决

TL; DR:

git config core.autocrlf false && git add --renormalize . && git reset --hard

缘起

Hexo 下大部分项目都在使用 Travis CI 在 Linux 环境、使用 Appveyor 在 Windows 环境完成单元测试。为了便于管理,我在 Hexo 核心团队中提出提案,在未来的几个月内逐步将 Hexo 的 Windows 单元测试从 Appveyor 的 Windows 环境迁移到 Travis 的 Windows 环境。按照提案,先在部分项目上开展 Travis Windows 的测试,第一个就是我维护的 hexo-filter-nofollow 插件。

修改 .travis.yml 中 OS 的设置后进行测试,Travis CI 上 Linux 的 Build 正常、但是 WIndows 的 Build 全部都 Fail 了:ESLint 报错 error Expected linebreaks to be 'LF' but found 'CRLF' linebreak-style

分析

问题很简单,看日志就知道了:行尾的换行符转换问题。CRLF 和 LF 都是什么已经没必要再冗笔解释了。写了可能有助于这篇文章的 SEO,但是没啥必要,我的博客在 Google 的权重已经足够高了

Git for Windows 在安装时提供了三个选项,方便不同开发者跨平台开发:

  • Checkout Windows-style, commit Unix-style line endings - 在 checkout(自然包括 git clone)时使用 CRLF 换行符、用于本地开发,在 commit 时使用 LF 换行符(本地文件仍然保留 CRLF 换行符)
  • Checkout as-is, commit Unix-style line endings - 在 checkout 时跟随来源文件的换行符,但是 commit 时使用 LF 换行符(本地文件的换行符不改动)
  • Checkout as-is, commit as-is - 不论 checkout 还是 commit 时都保留原始的换行符

几乎所有 Experienced Git Users 都会选择后面两个选项(绝大部分项目的代码规范都要求使用 LF 换行符、Windows 上大部分 IDE 也都支持 LF 换行符,没理由不用),第一种选项可能是为了照顾使用记事本开发的用户但是 Git for Windows 安装时选项默认选中第一种。Travis 在初始化 Windows 构建时,目前也是采用的第一种且不可更改(环境初始化不可控)。

知道了 Git for Windows 的这个行为以后,就很容易解释问题是怎么出现的了:虽然 Repo 中所有文件都使用 LF 换行符,但是在 git clone 时被全部转换为了 CRLF 换行符,导致 ESLint 无法通过。

解决

解决的方案有两种,一种是编写 shell 将本地所有文件的 CRLF 换行符替换为 LF 换行符,另一种方法是「解铃还须系铃人」、用 Git 解决:

  1. 首先禁用 Git 配置中的换行符自动转换,直接使用 git config core.autocrlf false 即可
  2. 使用 git add --renormalize .根据 core.autocrlfgit 重整所有换行符
  3. 使用 git reset --hard 回到 HEAD

在 Travis CI 中,还可以限制只在 Windows 上的 Build 重整换行符,可以根据 Travis 提供的环境变量 $TRAVIS_OS_NAME 判断当成操作系统。所以最后只需要在 .travis.yml 中添加下述 shell 步骤即可:

- if [[ $TRAVIS_OS_NAME == "windows" ]]; then
git config core.autocrlf false && git add --renormalize . && git reset --hard;
fi

参考 hexo-filter-nofollow 的 PR #5

本文最后更新于 天前,文中所描述的信息可能已发生改变