Skip to main content

令人困擾的git autocrlf

Opass
A life well lived

跨平台的git repo換行問題應該可以列入「每個工程師都會踩到的十大問題」之一。整理一下自己的筆記。

設定範圍

  • 在任何地方下 git config --global core.autocrlf 會影響到所有專案
  • 在repo內下 git config core.autocrlf 只會影響到當前的repo

和WSL無關

不論是在windows的cmd與在WSL下git command, 基本上對autocrlf完全沒有影響。這兩種環境差異是在WSL建立檔案的時候預設會用linux line ending, cmd建立檔案是用windows line ending。

了解git的normalize

git的發明人是鼎鼎大名恨透windows的Linuz, 因此git文件中所謂的normalize, 意思是把index內的檔案的line ending轉化成unit style.

以Linux為中心思考autocrlf

思考git autocrlf的時候,最重要的事情是以Linux為中心去思考。

  1. git config core.autocrlf false 預設值false, 就是原本檔案是什麼line ending commit時就照存進去index內。如果你只在linux上使用完全沒有問題,但如果你的git repo是跨平台開發,就會發生有人commit windows style有人commit linux style,你checkout出來的檔案就會照原本commit進去的line ending,因此就會發生混亂。

    所以有人會建議,不管你是哪個平台的用戶,剛裝完git要改掉這個預設值

  2. git config core.autocrlf true commit進去的時候幫你轉成LF, checkout出來的時候幫你轉成CRLF,所以叫做auto crlf, 通常在windows上會套用此設定, WSL與cmd通通用同一個沒有問題。在linux環境套用這個就是自找麻煩。

  3. git config core.autocrlf input commit進去的時候幫你把輸入normalize(轉成LF),checkout出來的時候原封不動, 如果你是用linux環境, 用這個設定沒啥問題, 還可以避免不小心把crlf commit進去repo。windows用這個設定就是自尋煩惱,commit進去還是crlf結果checkout出來就變成lf, 不是自己找麻煩嗎?

如果專案已經一段時間

如果專案已經發生Unix style和Windows style的line ending混雜在一起的情況,建議會是照著git的設計走

  • index中的檔案都以unit style為基準,checkout出來時根據平台決定要不要crlf, windows環境就用autocrlf = true, linux環境就用input
  • 可以下git add --renormalize . git會協助把index中的crlf轉成lf,讓你再commit一次。
  • 如果檔案實在太多,原本大家都把crlf全部commit進repo,而且repo只有windows使用,那全部都用autocrlf=false也無妨,只是在用WSL開發的時候要注意不要把line ending是LF的再commit進去。
  • 用.gitattributes去規範是更強硬的作法,那應該是另一篇文章了

gotcha

commit的時候檔案不會改變line ending

只有重新從repo中checkout出來時才會,你可以rm該檔案再checkout回來看看

令人困惑的錯誤訊息

在windows上設定成autocrlf = true, 有時候git add Line ending是LF的檔案,會跳出 warning: LF will be replaced by CRLF.的訊息,這是個令人困惑的訊息,你會想說明明就是把CRLF轉成LF並存起來,到底為什麼要把他換成CRLF?

可以參考stackoverflow Windows git “warning: LF will be replaced by CRLF”, is that warning tail backward?

這個錯誤訊息你可以想成,他其實是git add時會去trigger CRLF檢查,如果是LF,再下次checkout時要轉成CRLF,所以就跳這個訊息。無視就可以了。關於此問題的原因可以參考官方文件 https://git-scm.com/docs/gitattributes 中的節錄

git add itself does not touch the files in the work tree, the next checkout would, so the safety triggers;