源起
一直想在 GitHub 上發布項目、參與項目,但 Git 這貨比較難學啊。買了一本《Git 權威指南》,翻了幾頁,媽呀,那叫一個復雜,又是 Cygwin 又是命令行的,嚇得我不敢學了。
終于某天發現 GitHub 還有一個 Windows 客戶端,試了一下還挺好用。不需要掌握太多的 Git 原理和命令,也可以在 GitHub 上麻溜建項目了,甚是歡喜??墒呛镁安婚L,第一次參與開源項目就出洋相了。
經過
小心翼翼地 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,輸入以下命令,再敲回車即可:
原文轉自:https://github.com/cssmagic/blog/issues/22