Git for Windows でレポジトリー上の CR LF を LF に変換する手順

Git for Windows では改行コードが「レポジトリー上は LF」「ワーキング ディレクトリーは CR LF」となるように、git config の core.autocrlftrue となる状態でインストールされる (インストーラーでデフォルトの [Checkout Windows-style, commit Unix-style line endings] を選択した場合)。

Windows 以外の文化圏の人は CR LF を見ると CR がゴミに見えるので、妥当な設定だろう。

標準設定の autocrlftrue のときに、レポジトリー上に CR LF なファイルが紛れ込んでいないか調べたり、紛れ込んだ CR LF を LF に変換したかったのだけど、この手順が少しややこしかったので記事にまとめておく。

(autocrlffalse にして clone したらすぐに分かる…という話なんだけど、大きなレポジトリーを clone しなおすのはストレスフルなので、その場で確認する手順を調べてみた)

※ Git for Windows は 1.9 と 1.8.4 で検証した

レポジトリー上に CR LF のファイルがあるか調べたい

レポジトリー上のファイルの改行コードは LF で統一しているつもりなのに、CR LF のファイルが混ざりこんでたら悲しい。

autocrlftrue な状態で、レポジトリー上に CR LF のファイルが入ってないか調べるには次のようにする。

$ git grep --cached -I $'\r'

オプションの補足:

  • --cached を指定しないと、ワーキング ディレクトリー上のファイルから CR を探してしまう。つまり、core.autocrlftrue な状態では、すべての改行がヒットしてしまう。
  • -I でバイナリー ファイルを無視している。

実行例

https://gist.github.com/nitoyon/9808563 に CRLF と LF のファイルの 2 つがあるレポジトリーを用意してみた。

core.autocrlftrue な状態で clone すると、両方のファイルが CRLF でチェックアウトされる。

この状態で上記のコマンドを実行してみると、CR LF のほうだけが引っかかる。

$ git grep --cached -I $'\r'
crlf-test.txt:End of Line Character Test^M
crlf-test.txt:^M
crlf-test.txt:Which do you like CR LF or LF?^M
crlf-test.txt:^M
crlf-test.txt:This file uses "CR LF"!!!!^M
crlf-test.txt:^M
crlf-test.txt:Clone me!^M

めでたし。

レポジトリー上の CR LF を LF に変換したい

万が一、レポジトリー上に CR LF を発見したら、LF に統一しよう。

こちらも core.autocrlftrue になっている状態からの手順を示しておく。

  1. 一時的に core.autocrlffalse に設定する。

    $ git config core.autocrlf false
    
  2. LF でチェックアウトするために、ワーク ディレクトリーのファイルを全部削除してから、チェックアウトする (一度削除しないと反映されないことがあった!!)。

    $ rm -rf .
    $ git checkout .
    
  3. CR LF になっているファイルを何らかのエディターで LF に変換する。

  4. コミットする。

    $ git add . && git commit
    
  5. autocrlf の設定を戻す。

    $ git config core.autocrlf true
    

実行例

再び、https://gist.github.com/nitoyon/9808563 で試してみる。

作業完了後の diff はこんな感じになる。

$ git diff HEAD~
diff --git a/crlf-test.txt b/crlf-test.txt
index ad9608a..85a3c62 100644
--- a/crlf-test.txt
+++ b/crlf-test.txt
@@ -1,7 +1,7 @@
-End of Line Character Test
-
-Which do you like CR LF or LF?
-
-This file uses "CR LF"!!!!
-
-Clone me!
+End of Line Character Test
+
+Which do you like CR LF or LF?
+
+This file uses "CR LF"!!!!
+
+Clone me!

違いが分かりにくい diff が表示されていて悲しい。git の diff では CR があると ^M として警告してくれるはずなんだけど、^M が表示されるのは + から始まる行だけのようだ。今回のような「CR LF が LF になった」ケースでは CR があるのは - の行なので ^M は表示してくれない…。

--ignore-space-at-eol を指定して行末スペースの変更を無視したら、diff が消え去るので、うまくいっていると信じる。

$ git diff --ignore-space-at-eol HEAD~

git grep でも CR を見つけられなくなるので、うまくいっていると信じる。

$ git grep --cached -I $'\r'

まとめ

Windows はつらいよ。