GitHub 第一坑:换行符自动转换

源起

一直想在 GitHub 上发布项目、参与项目,但 Git 这货比较难学啊。买了一本《Git 权威指南》,翻了几页,妈呀,那叫一个复杂,又是 Cygwin 又是命令行的,吓得我不敢学了。

终于某天发现 GitHub 还有一个 Windows 客户端,试了一下还挺好用。不需要掌握太多的 Git 原理和命令,也可以在 GitHub 上麻溜建项目了,甚是欢喜。可是好景不长,第一次参与开源项目就出洋相了。

经过

小心翼翼地 Fork 了朴灵大大 (@JacksonTian) 的 EventProxy 项目,本地改好提交,同步到服务器,怀着激动的心情发出 Pull Request……这时发现问题了。我发现 diff 图表显示的更新并不仅是我修改的那几行,而是整个文件都显示为已修改。(下图为示意图)

这看起来很奇怪啊,于是赶紧撤回 Pull Request,自己闷头找原因。

初步定位是文件的换行符问题,因为我发现本地的文件是 Windows 换行符,但很显然大家现在做项目都是用 UNIX 换行符啊。这是一大疑点,于是在反复对比 Web 端和本地的各个文件、各个版本之后,基本定位到了问题所在。

背景

在各操作系统下,文本文件所使用的换行符是不一样的。UNIX/Linux 使用的是 0x0A(LF),早期的 Mac OS 使用的是0x0D(CR),后来的 OS X 在更换内核后与 UNIX 保持一致了。但 DOS/Windows 一直使用 0x0D0A(CRLF)作为换行符。(不知道 Bill Gates 是怎么想的,双向兼容?)

这种不统一确实对跨平台的文件交换带来麻烦。虽然靠谱的文本编辑器和 IDE 都支持这几种换行符,但文件在保存时总要有一个固定的标准啊,比如跨平台协作的项目源码,到底保存为哪种风格的换行符呢?

Git 作为一个源码版本控制系统,以一种(我看起来)有点越俎代庖、自作聪明的态度,对这个问题提供了一个“解决方案”。

Git 由大名鼎鼎的 Linus 开发,最初只可运行于 *nix 系统,因此推荐只将 UNIX 风格的换行符保存入库。但它也考虑到跨平台协作的场景,并且提供了一个“换行符自动转换”功能。

这个功能默认处于“自动模式”,当你在签出文件时,它试图将 UNIX 换行符(LF)替换为 Windows 的换行符(CRLF);当你在提交文件时,它又试图将 CRLF 替换为 LF。

(看明白了吗?一个版本控制系统会在你不知不觉的情况下修改你的文件。这 TM 简直酷毙了,对吧?)

缺陷

Git 的“换行符自动转换”功能听起来似乎很智能、很贴心,因为它试图一方面保持仓库内文件的一致性(UNIX 风格),一方面又保证本地文件的兼容性(Windows 风格)。但遗憾的是,这个功能是有 bug 的,而且在短期内都不太可能会修正。

问题具体表现在,如果你手头的这个文件是一个包含中文字符的 UTF-8 文件,那么这个“换行符自动转换”功能 在提交时是不工作的(但签出时的转换处理没有问题)。我猜测可能这个功能模块在处理中文字符 + CRLF 这对组合时直接崩溃返回了。

这可能还不是唯一的触发场景(毕竟我没有太多精力陪它玩),但光是这一个坑就已经足够了。

踩坑

这是一个相当大的坑,Windows 下的中文开发者几乎都会中招。举个例子,你在 Windows 下用默认状态的 Git 签出一个文件,写了一行中文注释(或者这个文件本来就包含中文),然后存盘提交……不经意间,你的文件就被毁掉了。

因为你提交到仓库的文件已经完全变成了 Windows 风格(签出时把 UNIX 风格转成了 Windows 风格但提交时并没有转换),每一行都有修改(参见本文开头的示意图),而这个修改又不可见(大多数 diff 工具很难清楚地显示出换行符),这最终导致谁也看不出你这次提交到底修改了什么。

这还没完。如果其他小伙伴发现了这个问题、又好心地把换行符改了回来,然后你又再次重演上面的悲剧,那么这个文件的编辑历史基本上就成为一个谜团了。

由于老外几乎不可能踩到这个坑,使得这个 bug 一直隐秘地存在着。但在网上随便搜一下,就会发现受害者绝对不止我一个,比如 这位大哥的遭遇 就要比我惨痛得多。

防范

首先,不要着急去整 Git,先整好自己。你的团队需要确定一个统一的换行符标准(推荐使用 UNIX 风格)。然后,团队的成员们需要分头做好准备工作——配置好自己的代码编辑器和 IDE,达到这两项要求:

  • 在新建文件时默认使用团队统一的换行符标准
  • 在打开文件时保持现有换行符格式不变(不要做自动转换)

这样一方面可以最大程度保证项目代码的规范一致,另一方面,即使现有代码中遗留了一些不规范的情况,也不会因为反复转换而导致混乱。(当然,作为一个强迫症患者,我还是祝愿所有的项目从一开始就步入严谨有序的轨道。)

接下来,我们就可以开始调教 Git 了。我的建议是, 完全关掉这个自作聪明的“换行符自动转换”功能。关闭之后,Git 就不会对你的换行符做任何手脚了,你可以完全自主地、可预期地控制自己的换行符风格。

下面主要针对不同的 Git 客户端,分别介绍一下操作方法。

Git for Windows

这货由 Git 官方出品,在安装时就会向你兜售“换行符自动转换”功能,估计大多数人在看完华丽丽的功能介绍之后会毫不犹豫地选择第一项(自动转换)。请千万抵挡住诱惑,选择最后一项(不作任何手脚)。

如果你已经做出了错误的选择,也不需要重新安装,可以直接使用命令行来修改设置。很简单,直接打开这货自带的命令行工具 Git Bash,输入以下命令,再敲回车即可:


1

git config --global core.autocrlf false

TortoiseGit

很多从 TortoiseSVN 走过来的同学很可能会选用 TortoiseGit 作为主力客户端,那么也需要配置一下。在 Windows 资源管理器窗口中点击右键,选择“TortoiseGit → Settings → Git”,做如下设置。

(由于 TortoiseGit 实际上是基于 Git for Windows 的一个 GUI 外壳,你在上一节所做的设置会影响到上图这些选项的状态,它们可能直接就是你所需要的样子了。)

GitHub 的 Windows 客户端

它是今天的第二被告。这货很容易上手,很适合小白,我主要用它来一键克隆项目到本地。可能正是为了维护简洁易用的亲切形象,这货并没有像 TortoiseGit 那样提供丰富的选项(对“换行符自动转换”这样的细节功能完全讳莫如深啊,我这样的小白死了都不知道怎么死的……)。因此,我们需要手动修改一下它的配置。

GitHub 的 Windows 客户端实际上也是一个壳,它自带了一个便携版的 Git for Windows。这个便携版和你自己安装的 Git for Windows 是相互独立的,不过它们都会使用同一个配置文件(实际上就是当前用户主目录下的 .gitconfig 文件)。

所以如果你已经配置好了自己安装的 Git for Windows,那就不用操心什么了。但如果你的机器上只装过 GitHub 的 Windows 客户端,那么最简单的配置方法就是手工修改配置文件了。

修改 Git 的全局配置文件

进入当前用户的主目录(通常 XP 的用户目录是 C:\Documents and Settings\yourname,在 Vista 和 Win7 下是C:\Users\yourname),用你最顺手的文本编辑器打开 .gitconfig 文件。

在 [core] 区段找到 autocrlf,将它的值改为 false。如果没找到,就在 [core] 区段中新增一行:(最终效果见图)


1

autocrlf = false

事实上上面介绍的所有命令行或图形界面的配置方法,最终效果都是一样的,因为本质上都是在修改这个配置文件。

还有

关掉了 Git 的“换行符自动转换”功能就万事大吉了吗?失去了它的“保护”,你心里会有点不踏实。你可能会问:如果我不小心在文件中混入了几个 Windows 回车该怎么办?这种意外可以防范吗?

事实上 Git 还真能帮你制止这种失误。它提供了一个换行符检查功能(core.safecrlf),可以在提交时检查文件是否混用了不同风格的换行符。这个功能的选项如下:

  • false - 不做任何检查
  • warn - 在提交时检查并警告
  • true - 在提交时检查,如果发现混用则拒绝提交

我建议使用最严格的 true 选项。

和 core.autocrlf 一样,你可以通过命令行、图形界面、配置文件三种方法来修改这个选项。具体操作就不赘述了,大家自己举一反三吧。

最后

你可能还会问,如果我的编辑器一不小心把整个文件的换行符都转换成了另一种格式怎么办?还能预防吗?

这……我就真帮不了你了。所以还是建议大家在提交文件之前多留心文件状态:

如果发现变更行数过多,而且增减行数相同,就要警惕是不是出了意外状况。被图形界面惯坏的孩子往往缺乏耐心,对系统信息视而不见,看到按钮就点,容易让小疏忽酿成大事故。所以高手们青睐命令行,并不是没有道理的。

时间: 2024-10-29 01:07:13

GitHub 第一坑:换行符自动转换的相关文章

Git坑换行符自动转换 [转载]

转自https://www.cnblogs.com/zjoch/p/5400251.html 源起 一直想在 GitHub 上发布项目.参与项目,但 Git 这货比较难学啊.买了一本<Git 权威指南>,翻了几页,妈呀,那叫一个复杂,又是 Cygwin 又是命令行的,吓得我不敢学了. 终于某天发现 GitHub 还有一个 Windows 客户端,试了一下还挺好用.不需要掌握太多的 Git 原理和命令,也可以在 GitHub 上麻溜建项目了,甚是欢喜.可是好景不长,第一次参与开源项目就出洋相了.

github 换行符自动转换功能

最近想把自己的一个Qt工程同步到github上,但是当自己把代码从仓库中签出来的时候编译的时候总是出现一些很奇葩的错误,一开始以为是源文件编码的问题,改了编码以后问题还是没有解决,我比较了一下两个工程中的文件,真是一比吓一跳啊 windows换行是\r\n,十六进制数值是:0D0A.LINUX换行是\n,十六进制数值是:0A Git 由大名鼎鼎的 Linus 开发,最初只可运行于 *nix 系统,因此推荐只将 UNIX 风格的换行符保存入库.但它也考虑到跨平台协作的场景,并且提供了一个“换行符自

windows和linux中换行符的转换

数据开发平台使用上传脚本报错:保存失败,文件编码格式不正确,请修改文件换行符为Unix终束符! 修改方式:DOS系统下,使用文本编译器另存为,然后选择换行符为unix终束符. 解释: windows 文件的换行符为:[CR][LF] Linux和Unix文件的换行符为:[LF] 有些需要转换使用,如修改或替换安卓andriod的hosts文件,需要保证换行符为Unix形式才能使用. 其中一种办法是在linux系统中重新保存一份文件: 但是:如何在windows系统中,转换成Unix / Linu

git crlf、lf自动转换引起的问题

??项目组最近加了一个新功能到代码中,使用flyway记录数据库版本变更,,,该工具会记录每次数据库结构的修改并生成sql文件存在指定目录上(当然必须用它来变更数据库,外部的变更它是无法感知的),然后每次启动时flyway会检查使用的数据库和当前项目代码中的sql变更版本是否一致,一致正常启动,不一致中如果是数据库落后将会更新数据库(这样能够保证代码在任何地方运行数据库都是一致的),否则就报错了.数据库中有一张表记录版本信息,如下图: 同时本地代码中也有一个文件夹保存每次操作的sql语句,如下图

SQLLoader8(加载的数据中有换行符处理方法)

SQLLDR加载的数据中有换行符处理方法1.创建测试表: CREATE TABLE MANAGER( MGRNO NUMBER, MNAME VARCHAR2(30), JOB VARCHAR2(30), REMARK VARCHAR2(1000) ); 2.创建控制文件我们可以通过控制文件,在数据加载前处理remark列的数据,将用户指定的"\n"字符替换为chr(10),即标准换行符,创建控制文件如下: LOAD DATA INFILE 'D:\testSqlLoader\ldr_

替换textarea文本值中的换行符

function replaceVal() { var _content = $("#txtCustom").val().replace(/\n/g, "@"); $("#txtCustom").val(_content); } 问题:我的需求类似于现在寄快递时在公众号填写信息的功能,即直接将信息粘贴到文本框中,自动识别信息,然后填写. 不过我的更简单,我只要得到输入的信息,保持其换行的状态,放到其他地方使用即可. 所以我这里只是简单的将换行符“

菜鸟教程之工具使用(八)——EGit禁止自动转换回车换行符

众所周知,Windows和Linux系统的回车换行是不一样的.想要进一步了解它们的可以阅读下面的介绍,不感兴趣的可以直接跳过. 产生背景 关于"回车"(carriage return)和"换行"(line feed)这两个概念的来历和区别.在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符.但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符.要是在这0.2秒里面,又有新的字符传过

git 自动转换行符的坑爹案例

本人写的脚本都是在unix上运行的,但是编写有时候喜欢使用Git拉去到windows的ide进行编写,毕竟我的unix只有命令行的没有ide, 殊不知有一天我的sh执行时出现错误 -bash: ./dailytask.sh: /bin/sh^M: bad interpreter: 没有那个文件或目录 使用vim的命令:set ff?来查看文件格式发现已经是dos,修改格式为unix,命令如下:set ff=unix 接着再运行就好了 如果文件很多都修改成dos格式了,请示用dos2unix来进行

编码语系转换与换行符转换

1.编码语系转换 常见中文编码语系有gb2312.big5.utf8,有时出于某种目的,一个文件要在不同的编码语系间转换,用iconv命令即可. $ iconv -l -l列出支持的编码语系. $ iconv -f encoding -t encoding filename [-o file] -f表示原编码格式,-t表示目标编码格式,-o表示stdout到文件. 还有一个好用的命令file,可查看文件编码格式和换行符. $ file filename 2.换行符转换 Windows与Linux