Git diff 換行符問(wèn)題
背景
由于一些特殊的原因,目前代碼是運(yùn)行在windows上的,開(kāi)發(fā)是在mac上,但上傳的代碼庫(kù)里的文件里的換行符卻是有windows下的也有l(wèi)inux下的,為了保證代碼的正常運(yùn)行,就沒(méi)敢批量的替換,統(tǒng)一所有文件的換行符。
問(wèn)題
windows運(yùn)行代碼,mac下開(kāi)發(fā),從倉(cāng)庫(kù)檢出的代碼修改完后,照例執(zhí)行g(shù)it diff查看下差異,發(fā)現(xiàn)整個(gè)文件內(nèi)容都修改了,于是經(jīng)過(guò)一番查證,有了今天這篇記錄。
原因
在Windows上編程,可能會(huì)在某個(gè)時(shí)候遇到行尾問(wèn)題。這是因?yàn)閃indows文件中的換行符同時(shí)使用回車符和換行符,而macOS和Linux系統(tǒng)只使用換行符。Windows上的許多編輯器用CRLF地替換現(xiàn)有的LF風(fēng)格的行結(jié)尾,或者在用戶點(diǎn)擊Enter鍵時(shí)插入兩行結(jié)束字符。
由于不同的系統(tǒng)之間的換行符不同,windows換行符是CRLF,而linux下是LF,這樣就導(dǎo)致由于換行符的不同,git diff查看差異的時(shí)候整個(gè)文件都被修改了。
那么與git又有什么關(guān)系呢,是這樣的,我們從遠(yuǎn)程倉(cāng)庫(kù)拉下來(lái)代碼,比如我的,檢出的時(shí)候是CRLF,然而我在地修改完代碼后,本地是mac系統(tǒng),是以LF為換行符的,這個(gè)時(shí)候編輯器就幫我改成了LF換行符(也可以自己手動(dòng)設(shè)置換行符),這個(gè)時(shí)候我在用git diff 查看的時(shí)候自然就是整個(gè)文件內(nèi)容都被修改了。
而當(dāng)我忽略問(wèn)題,添加到暫存區(qū)的時(shí)候則發(fā)生了一條警告如下(當(dāng)然,如果你選擇使用編輯器修改換行符后,自然也不會(huì)存在這條警告了):
╭─chujiu@192.168.2.111 ~/project/okrie/printer-web ?test*?
╰─? git add .
fatal: 文件 common/classes/log.php 中的 LF 將被 CRLF 替換
這個(gè)警告是說(shuō),編輯器給我改成了LF換行符后,在添加到暫存區(qū)的時(shí)候,git會(huì)自動(dòng)幫我轉(zhuǎn)回我檢出代碼時(shí)的換行符。那么為什么會(huì)有這樣一個(gè)提示呢?
這與core.autocrlf和core.safecrlf 以及 core.eol這三個(gè)配置有關(guān)系。
core.autocrlf
git可以自動(dòng)將CRLF行尾轉(zhuǎn)換為L(zhǎng)F,如果在Windows系統(tǒng)上,core.autocrlf設(shè)置為true,就可以在檢出代碼的時(shí)候?qū)F結(jié)尾轉(zhuǎn)換為CRLF,提交的時(shí)候轉(zhuǎn)為L(zhǎng)F。(我們平常寫(xiě)代碼的是我們的工作區(qū),但我們運(yùn)行g(shù)it add 的時(shí)候是添加到暫存區(qū),最后提交的時(shí)候把暫存區(qū)的內(nèi)容轉(zhuǎn)換為L(zhǎng)F,而不是修改工作區(qū)的內(nèi)容。但檢出代碼的時(shí)候是把倉(cāng)庫(kù)里的代碼轉(zhuǎn)換為CRLF到我們的工作區(qū))
╭─chujiu@192.168.2.111 ~/project/okrie/printer-web ?test*?
╰─? git config --global core.autocrlf true
如果在使用LF的Linux or macOS,檢出代碼的時(shí)候不希望自動(dòng)轉(zhuǎn)換,但是如果有意外的文件帶進(jìn)了CRLF,那么你肯定希望可以修復(fù)它,這個(gè)時(shí)候就可以設(shè)置core.autocrlf為input,意思就是檢出代碼的時(shí)候不用轉(zhuǎn)換,提交的時(shí)候轉(zhuǎn)換為L(zhǎng)F。
╭─chujiu@192.168.2.111 ~/project/okrie/printer-web ?test*?
╰─? git config --global core.autocrlf input
如果設(shè)置了false,這個(gè)設(shè)置應(yīng)該會(huì)在Windows簽出中留下CRLF結(jié)尾,但在macOS和Linux系統(tǒng)以及存儲(chǔ)庫(kù)中會(huì)留下LF結(jié)尾。
如果開(kāi)發(fā)和運(yùn)行都是windows系統(tǒng),那么可以關(guān)閉此功能,通過(guò)將配置值設(shè)置為false在存儲(chǔ)庫(kù)中記錄回車,但如果你運(yùn)行的環(huán)境是windows,但開(kāi)發(fā)是linux,那修改文件后,編輯器會(huì)幫你自動(dòng)更改換行符就出問(wèn)題了。
╭─chujiu@192.168.2.111 ~/project/okrie/printer-web ?test*?
╰─? git config --global core.autocrlf false
core.safecrlf [參考官方文檔][https://git-scm.com/docs/git-config]
如果設(shè)置為true(不是true忽略這個(gè)參數(shù)),git會(huì)檢查CRLF轉(zhuǎn)換是否正常,如果不正常則給一個(gè)警告, 怎么才是不正常的呢,如果core.autocrlf=true,那么我們檢出代碼到工作區(qū)的文件都應(yīng)該是CRLF,如果工作區(qū)的文件有LF就會(huì)給一個(gè)警告,還有g(shù)it也拒絕提交混合換行符的文件。git在低版本中只是一個(gè)警告,但還是可以提交的,但高版本直接就不讓提交了。
CRLF轉(zhuǎn)換有可能損壞數(shù)據(jù)。啟用后,Git將在提交期間將CRLF轉(zhuǎn)換為L(zhǎng)F,在簽出期間將LF轉(zhuǎn)換為CRLF。但是Git無(wú)法重新創(chuàng)建在提交之前包含LF和CRLF的混合文件。對(duì)于文本文件,這是正確的做法:它更正了行尾,這樣我們?cè)诖鎯?chǔ)庫(kù)中只有LF行尾。但對(duì)于意外分類為文本的二進(jìn)制文件,轉(zhuǎn)換可能會(huì)損壞數(shù)據(jù)??梢酝ㄟ^(guò)在.gittattributes中顯式設(shè)置轉(zhuǎn)換類型來(lái)輕松地修復(fù)它。但對(duì)于,清理帶有混合行尾的文本文件的預(yù)期效果和損壞二進(jìn)制文件的預(yù)期效果無(wú)法區(qū)分。在這兩種情況下,CRLF都以不可逆的方式被移除,對(duì)于文本文件,這是正確的做法,因?yàn)镃RLFs是行尾,而對(duì)于二進(jìn)制文件,轉(zhuǎn)換CRLF會(huì)損壞數(shù)據(jù)。
core.eol
設(shè)置要在工作目錄中用于標(biāo)記為文本的文件的行尾類型(通過(guò)設(shè)置text屬性,或通過(guò)設(shè)置text=auto和Git auto將內(nèi)容檢測(cè)為文本)。值是lf、crlf和native。默認(rèn)native,即使用平臺(tái)的。如果core.autocrlf設(shè)置為true或input,則忽略此值。
.gittattributes [參考1][https://help.github.com/en/github/using-git/configuring-git-to-handle-line-endings][參考2][https://git-scm.com/docs/gitattributes]
結(jié)論
- 如果工作區(qū)是mac/linux就別設(shè)置core.autocrlf了,這個(gè)東西是給windows用的,比如有人用windows開(kāi)發(fā),就可以設(shè)置為true,這樣他提交的時(shí)候轉(zhuǎn)化為lf,始終保持倉(cāng)庫(kù)里的代碼是統(tǒng)一的換行符。
- 如果你不幸跟我一樣倉(cāng)庫(kù)的代碼里的換行符都不統(tǒng)一,那只能想辦法把倉(cāng)庫(kù)里的文件換行符統(tǒng)一了,但這可能會(huì)帶來(lái)風(fēng)險(xiǎn)。如果不想統(tǒng)一就保持原狀,那么在linux下本地用編輯器修改帶有crlf文件的,就要在修改完后把換行符改為crlf后再提交,注意中文的編碼,因?yàn)榫庉嬈鲿?huì)自動(dòng)把我們工作區(qū)改為lf,否則這樣git diff 出現(xiàn)的還是會(huì)是整個(gè)文件修改,但這并不是好辦法。
- 也可以簡(jiǎn)單直接win下也用lf,設(shè)置一個(gè).editorconfig文件,設(shè)置換行符號(hào)為lf,然后設(shè)置core.autocrlf為false,不過(guò)同樣不能解決倉(cāng)庫(kù)里代碼換行符不一致的情況,這個(gè)可以利用編輯器把所有的換行符更換下,這個(gè)需要你的編輯器有支持的插件,[參考][https://editorconfig.org/]。
- 具體的換行符是哪個(gè),可以利用notepad++查看。視圖-顯示符號(hào)-顯示所有文件符號(hào),即可。