使用git attributes正規化專案換行字元
各位開發者所熟悉的專案版控工具git, 無論是一人專案或多人合作專案都有其用武之地。在多人專案中,數名開發者各自在自己的作業系統上進行開發後,將成果發布到repository 上。其他的開發者則將新的內容拉到自己的環境中,再繼續自己的開發作業。這乍聽之下沒什麼問題,多數情況下也不會有什麼問題──直到你遇到這個詭異的現象:
看起來一頓瞎忙的commit log
看起來像是把這個文件徹頭徹尾地做了更改,仔細一看卻發現根本什麼都沒變!到底是怎麼一回事呢?
寫程式的人都知道,每一行文字的最後都會跟著一個螢幕上看不到的換行字元‘\n’ (LF). 其實,這僅限Unix類的作業系統,如Ubuntu, CentOS, macOS…。由MS-DOS衍生而來的Windows系統使用編碼格式不同,當使用者按下enter鍵時,實際輸入文件的字元是‘\r\n’ (CRLF), 分別代表carriage return (回車) 和line feed (換行). 回車與換行的由來與舊式印表機技術有關,有興趣者可參考維基百科關於換行字元的文章。
許多現代化的文字編輯器都有考慮到這點,為了避免在編輯/閱讀不同平台所產生的文件時發生錯誤,都會有自動轉換編碼的功能,確保文件的換行字元與現在的作業系統一致。雖然這對於使用者來說非常方便,卻會導致這些更動被git紀錄下來,導致commit裡出現許多無意義的增刪。
使用vim編輯ㄧ份有‘\r\n’也有‘\n’的檔案,‘\r’就會以^M的形式出現了
現在知道了這個現象背後的原因,該來說明如何避免他再度發生了。過去的作法是設定core.autocrlf, 但這仰賴於專案中的每個開發者都使用不衝突的設定。更好的作法是在專案中加入.gitattributes來定義各個檔案的屬性,git便會根據該屬性將專案文件的換行字元進行正規化。撰寫方式可參考適用網站開發專案的.gitattributes。其中第一個欄位是指定的檔案名稱,後面分別以獨立欄位定義檔案屬性。以下簡單說明檔案中不同屬性的用途:
- 僅設定text屬性的檔案:git commit時會將此類檔案的CRLF正規化成LF, 並在checkout時轉換成本機系統對應的換行字元。這是最常用的屬性,建議套用於跨平台程式碼、文件等等。
- 設定text, eol=lf的檔案:git commit時會將此類檔案的CRLF正規化成LF, checkout時不再進行換行字元的轉換。建議套用於僅限unix系統的程式碼,如bash script.
- 設定text, eol=crlf的檔案:git commit時會將此類檔案的CRLF正規化成LF, checkout時再將LF轉換成CRLF. 適用於Windows限定的檔案,如bat script, cmd script.
- 僅設定binary屬性的檔案:git不會對此檔案進行任何正規化,建議套用於exe檔、影音檔等等絕對不能隨意更動任何一個字元的檔案。
- 設定text=auto的檔案:交由git判斷是否應進行正規化(如同僅設定text屬性的檔案),或是不對此檔案進行任何改動(如同僅設定binary屬性的檔案)。
關於.gitattributes的詳細說明,可參考官方文件。
新建的專案中只要加入.gitattributes並妥善設定好檔案屬性,就能一勞永逸地解決跨平台合作專案的換行字元正規化問題。若是已經在進行中的專案,則有必須額外採取的步驟。
- 確保目前的working directory是乾淨的狀態。若有進行中的工作,請先完成並commit.
- 新增.gitattributes並妥善設定好檔案屬性。
- 執行git add . –renormalize 進行正規化。
- 執行git commit 將正規化的結果存入repository.
操作過程範例如下圖:
即使目前的開發團隊都使用同一個作業系統,難保未來加入的開發者也如此。此外,專案中或許會引入其他專案的檔案,而你無法保證這些檔案的換行字元和你的系統相符。希望看完這篇文章後的開發者們會在git專案中加入這個便利的檔案,不再把重要的編輯歷史埋沒在commit diff 中數千行無意義的增刪紀錄,讓版控工具可以發揮其最大的效能。
想得到更多新知嗎?記得追蹤歐斯瑞fb粉絲團及IG,也記得訂閱電子報,就不會錯過我們最新的文章分享呦!若有任何問題,也歡迎隨時與我們聯繫。
我要留言