The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

Git 在 Windows 平台處理斷行字元 (CRLF) 的注意事項

在 Windows 平台使用 Git 時,偶爾會遇到斷行字元的問題,之前遇到時並不知道為什麼會這樣,只覺得怪怪的,最近終於釐清這個問題,所以決定撰文解釋一下來龍去脈,以免有人還遇到相同的問題。

因為 Git 版本控管早期是為了維護龐大的 Linux kernel 而設計而成的,所以絕大部分的使用環境都是 Linux 平台,而在 Linux 平台下,文字檔案的斷行符號預設為 LF 字元 ( \n ) ( 0x0A )。不過,在 Windows 環境下,文字檔案的預設斷行符號卻是 CRLF ( \r\n ) ( 0x0D 0x0A ),比 Linux 多了一個字元。也就是說,如果你的軟體專案的原始碼總共有 100 萬行,這代表你如果用 CRLF 來儲存斷行字元,會多浪費 100 萬個位元組來儲存這些多餘的 CR ( \r ) 字元。因此,在使用 Git 工具的時候,通常建議你將 LF 當成文字檔案的斷行符號。

在 Windows 平台使用 Git 版本控管,Git for Windows 是一套必備工具,在安裝的時候,有個步驟是 Configuring the line ending conversions 這項,通常我們會選擇第一個選項,也就是 Checkout Windows-style, commit Unix-style line endings 選項。

這個選項會讓 git 指令在執行的時候,自動轉換斷行符號,從哪裡轉換呢?就是從 Git 版本庫中的檔案Git 工作目錄中的檔案自動轉換斷行符號。簡單來說,就是【當執行 git add 命令時,文字檔案中出現的 CRLF 斷行字元會自動被轉換成 LF 字元。而利用 git checkout 取出檔案到工作目錄時,則會自動將 LF 字元,轉換成 CRLF 字元】,這是一個自動轉換的程序,git 工具會自動幫你完成這些轉換,所以你幾乎不需要知道有這種設定存在。

如果你忘記在安裝時到底設定了哪一組,可以用以下指令進行查詢:

git config core.autocrlf

若回傳的結果不是 true 的話,可以用以下指令進行修改:( 通常 core.autocrlf 都設定在系統層級 )

git config --system core.autocrlf true

當然,如果你要設定在使用者層級也是可以的,如下指令:

git config --global core.autocrlf true

 

 

我前陣子在 GitHub 上曾經發現過一個 Landscaping With Frontend Development Tools 專案,這裡收集了上百個前端開發工具的大收集,索性直接翻譯成正體中文版,並取名為 各式 Web 前端開發工具整理。如果你想從 GitHub 直接將我的翻譯專案 複製 (clone) 回去,可以使用以下指令:

git clone https://github.com/doggy8088/frontend-tools.git

不過,詭異的是,我將專案複製回來後,在沒有進行任何修改的情況下,竟然檔案會有被修改過的跡象!

各位不覺得奇怪嗎?我第一次遇到的時候,只覺得 Git 怎麼怪怪的?是不是 Git for Windows 有 Bug 呢?

後來發現到,因為專案我是從 frontend-tools 給 fork 過來的,原本的專案就有一個 .gitAttributes 檔案,裡面定義了所有文字檔案都應該要自動轉換斷行符號,也就是要對文字格式進行 正規化 (normalize) 的意思: ( 該檔案的格式說明請參見 Git - Git Attributes )

* text=auto

也因為 .gitAttributes 檔案的存在,導致了 Git 在取出檔案的同時,也希望幫你把所有專案內的文字檔案進行正規化。

: 因為執行 git clone 時會隱含執行 git checkout 命令,如此一來你的工作目錄才有檔案!

重點就在於,以前我不知道要轉換甚麼,這個取出檔案的過程 git 幫我改了些甚麼?還是有其他原因?

現在,我終於知道了,首先我先取出在 目前最新版 ( HEAD ) 的 README.md 檔案,使用以下指令:

git show master:README.md > README.HEAD.md

然後比對了一下 git 幫我取出的 README.md 檔案,結果發現:兩個檔案一模一樣,完全沒有轉換,但執行 git status 指令時,它卻告訴我檔案被修改了!

後來才發現到 GitHub 上的 Dealing with line endings 文件,這才真相大白,原來事實的真相是:

因為 .gitAttributes 檔案定義了要對所有文字檔案進行正規化處理,所以儲存在版本庫中檔案內容必須以 LF 結尾,在工作目錄中的文字檔案必須以 CRLF 結尾,這就是「正規化」要做的事。而我們雖然工作目錄中的檔案是 CRLF 結尾,但版本庫中的檔案卻也是以 CRLF 結尾,那就不對了!

所以,他就是要讓你重新再 commit 一個版本,好讓 git 幫你完成正規化的程序,讓儲存在版本庫中的檔案改用 LF 當成文字檔案的斷行符號。

我們重新複製這個專案,然後修正字元,你可以參考以下指令執行的圖示:

我們要如何驗證這個過程真的有做到正規化的結果呢?請輸入以下指令取出目前版本庫中的 README.md 檔案,我們把檔案匯出到 test.txt 檔案中:

git show master:README.md > test.txt

最後再以 Notepad2 開啟該檔案,從右下角某一格可以看出該檔案的斷行符號為何,如果是 LF 的話,就代表正規化執行成功:

如下圖示:

 

心得分享

我一直都認為,在學習工具或技術的過程中,只要感覺到有「怪怪的」,基本上就是自己不夠了解他,當然也有可能是工具本身的 Bug,這些還是能夠透過一些方法進行驗證,最重要的還是對一套工具或一門技術的「核心觀念」是否真正理解,當掌握了來龍去脈,解題的方向自然會更加正確,也更容易找到解答。

我最近將 O’REILLY 的「 版本控制使用 Git (第二版) 」這本書給看完,當中學習到許多紮實的觀念,雖然中文翻譯的品質不太理想 (書中的專有名詞很少中英對照,導致看中文時不知道英文的原意為何,這會導致一定程度的閱讀障礙),但在中、英文版交互閱讀之下,閱讀的品質還是可以漸入佳境,最終吸收到較為完整的知識,整體上來說,還是推薦各位可以閱讀這本書!

 

建議繼續閱讀【Visual Studio Tools for Git 處理斷行字元 (CRLF) 的注意事項】一文。

 

相關連結