在不同 OS 底下共同編輯一個 git repository 時,可能就會出現這個問題,要解決該問題其實也很簡單,其原理及解決方法敬請聽我娓娓道來。
碰到的情況#
剛 clone 一個 git repository 時,卻發現檔案顯示已被修改過,正等待 commit。
當使用 git diff 查看時,卻看到幾乎每行的後面都顯示一個「^M
」。
簡述何為「換行符號」#
給不知道的朋友科普一個小知識:
其實在電腦儲存資料時,並沒有「換行」的概念,而我們所看見的「換行」其實本身也是一個「字元」。舉例如下方文字:
這是第一行 這是第二行
儲存在電腦當中其實是長類似這樣「
這是第一行\n這是第二行
」
(p.s. 這只是舉例,事實上不完全是,畢竟電腦只認得二進制)
而那個「\n
」便是常見用於表示換行符號的「Escape Character (跳脫字元)
」,也被寫作「LF
(Line Feed)」,ASCII Code 為「0x0A
」。
不同 OS 可能有著不同的規範#
如上所述,換行符號本身只是一個字元,至於要用哪個字元代表「換行」…
在不同的作業系統當中,可能有著不同的定義。
舉例來說:
- Windows:
\r\n
- Mac OS:
\r
- Mac OS X:
\n
- Linux:
\n
那麼當你在不同的作業系統編輯同一份檔案時,可能會需要「轉換」換行符號才能讓作業系統正確讀懂。
git diff 一堆 ^M 是什麼?#
這個問題通常是發生在用戶嘗試在 Linux 上編輯一個由 Windows 編輯過的檔案。
依照剛剛所提到的,Windows 的換行符號為「\r\n
」,而 Linux 則為「\n
」。
那麼舉例當文字「第一行\r\n第二行
」在 Windows 及 Linux 間會如何顯示呢?
答案是:
1# windows
2第一行
3第二行
4
5# Linux
6第一行\r
7第二行
由於 Windows 的換行符號比 Linux 多出了一個「\r
」,因此在 Linux 作業系統當中,依舊會將「\n
」解釋成換行,而「\r
」則原封不動保留。
這導致幾乎每行文字後方都會跟著一個「\r
」(注意,這是特殊符號表示,並不是真的顯示一個「\r
」)。
而這個「\r
」ASCII Code 為「0x0D
」,也寫作「CR
」,在 git 及 vim 當中以「^M
」表示。
p.s. 字元「
^
」在許多地方都表示ctrl
,所以「^M
」意思是ctrl
+M
。
解決方式:自動轉換 CRLF#
在 git 當中有一項設定可以用來自動將「\r\n
」當作「\n
」看待。
可以簡單的透過更改git 全域設定
來啟用該功能:
1git config --global core.autocrlf true
(p.s. 但在團隊開發上,更推薦的作法是更改「.gitattributes
」)
unix2dos & dos2unix#
補充說明,有兩個指令就是專門用來轉換換行符號的,分別是「unix2dos
」及「dos2unix
」。
unix2dos
:將 Linux 的「\n
」轉換為 Windows 的「\r\n
」dos2unix
:將 Windows 的「\r\n
」轉換為 Linux 的「\n
」
(p.s.「2
」有「to
」的意味)
詳細說明請見Wiki 維基百科
:https://en.wikipedia.org/wiki/Unix2dos
References#
- 《Did Mac OS Lion switch to using line feeds (LF ‘\n’) for line breaks instead of carriage returns (CR ‘\r’)? - Super User》https://superuser.com/questions/439440/did-mac-os-lion-switch-to-using-line-feeds-lf-n-for-line-breaks-instead-of
- 《處理 Git 斷行字元的問題 | Titangene Blog》https://titangene.github.io/article/git-auto-crlf.html
- 《newline - Make ‘git diff’ ignore ^M - Stack Overflow》https://stackoverflow.com/questions/1889559/make-git-diff-ignore-m