源起
一直想在 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
一樣,你可以通過命令行、圖形界面、配置文件三種方法來修改這個選項。具體操作就不贅述了,大家自己舉一反三吧。
最后
你可能還會問,如果我的編輯器一不小心把整個文件的換行符都轉換成了另一種格式怎么辦?還能預防嗎?
這……我就真幫不了你了。所以還是建議大家在提交文件之前多留心文件狀態:
如果發現變更行數過多,而且增減行數相同,就要警惕是不是出了意外狀況。被圖形界面慣壞的孩子往往缺乏耐心,對系統信息視而不見,看到按鈕就點,容易讓小疏忽釀成大事故。所以高手們青睞命令行,并不是沒有道理的。
不含病毒。www.avast.com |
留言列表