Git 在 Windows 平台的換行字元

這篇筆記記錄 Git 自動處理換行字元所衍生的問題,順便補充先前寫的筆記。

先前寫過一篇筆記:Git 的 core.autocrlf 參數。後來有一段時間都在用 TFS 和 Subversion,直到註冊了 TFS 免費雲端服務,又開始使用 Git。

可是我壓根兒忘了要去設定換行字元這件事。

於是,最近開始出現一個狀況:在不同的電腦上拉回新版本之後,在沒有改動任何檔案的情況下,執行 commit 命令,竟然會出現有些檔案異動過了,讓我提交至伺服器。更慘的是,有些用戶端機器的設定錯誤,以至於連二進位檔案(例如 .DLL)裡面的換行字元都被 Git 強制替換掉,導致 Visual Studio 專案出現編譯錯誤。

於是,這才又去複習了先前的筆記,以及網路上的一些文章。看看自己先前調查的結果是否還適用。其中當然也看了保哥寫的文章:Git 在 Windows 平台處理斷行字元 (CRLF) 的注意事項。在那篇文章裡面,保哥充分展現了研究精神,詳細說明了為什麼我們在使用 Git 時需要關心換行字元的議題。

既然已經有很好的參考資料,那麼在這篇筆記裡面,我就簡單記錄一下自己碰到的問題和應對方法。

先說結論:我不讓 Git 自動轉換任何換行字元,無論是純文字還是二進位檔案。

換行字元會咬人!

某次執行完 git pull 命令更新整個專案之後,Visual Studio 編譯時報錯一堆:Resolved file has a bad image, no metadata, or is otherwise inaccessible。如下圖:


既然是參考的組件有問題,直覺想到先試試用 nuget 把那些出問題的套件再裝一次。結果光是開啟 nuget 套件管理員都會出錯:


即使把 nuget 的 config 檔案裡面逐一刪掉一些套件參考,終於可以開啟套件管理員了。隨後再安裝某些套件時仍會出錯:


這是因為此專案有許多二進位檔案在經過 git 換行字元轉換之後被破壞了。下圖是我將出問題的專案之 nuget 套件目錄下的 System.Web.Mvc.dll 跟另一個專案的 dll 檔案比較的結果,可以看出 0x0D 和 0x0A 被轉成了 0x0A。


Git 沒有錯。錯在我沒注意到某台開發機器的 Git 設定不一樣——它被設定成預設將所有檔案的換行字元一律轉成 0x0A。

光是修正所有的二進位檔(包括圖片也都被破壞了)就費了好一番手腳,才確認所有的檔案皆已復原成正確格式。所以換行字元轉換的問題還是得注意一下,以免浪費寶貴的時間。

文字類型的檔雖然不至於像二進位檔案那樣可能引發嚴重問題,但如果 Git 認為你要它幫你自動處理換行字元的轉換,每次 commit 時就可能多出一些自己根本沒改過的檔案,這也挺煩的。下圖是用 kdiff3 工具比對兩個版本的差異,左邊的換行字元是 DOS 風格(亦即 CRLF),右邊則是 Unix 風格(亦即 LF),可以看出檔案中的換行字元被改過了。



預設是自動轉換 CRLF

Git 的預設行為是自動幫我們處理換行字元的轉換。為了避免每台機器設定不同而產生互相踩腳的情形,最好是在建立 repo(檔案庫)時就針對那個 repo 編寫適當的組態檔(.gitAttributes)。如此一來,無論檔案庫被複製到哪裡,設定都不會跑掉。

設定方法請參考這裡這裡、或這裡

修改檔案庫的 .gitAttributes 檔案時,我只是把原本預設的

* text auto

改成這樣:

* -text

也就是告訴 Git:別動我的換行字元,任何檔案都別去動!原本它是 LF 就 LF,原本是 CRLF 就照存 CRLF。

省略「重新正規化」的動作會怎樣?

改完換行字元轉換的設定之後,應該要對檔案庫執行重新正規化的動作。如果省略此步驟,就得靠自己手動修正各檔案。如果都不理它,將來 commit 時,TortoiseGit 會提示某些檔案的換行字元將被修改,如下圖:


如前面提過的,文字檔還好,但二進位檔案就可能會造成嚴重問題,不可輕忽。

參考資料

沒有留言:

技術提供:Blogger.
回頂端⬆️