改行コードCRLFとLFの違いと統一方法
改行コードは LF(\n・0x0A)とCRLF(\r\n・0x0D 0x0A)の2種類が現役です。 Unix/Mac/Gitの内部表現はLF、WindowsはCRLFが標準。混在するとdiffが全行差分になる・シェルスクリプトが動かないなどの実害が出ます。
LF (\n) is the Unix/Git standard; CRLF (\r\n) is the Windows standard. This guide covers the real-world breakage and how to normalize line endings with .gitattributes.
TL;DR
- チーム統一は
.gitattributesに* text=auto(リポジトリ側で強制、個人設定に依存しない) - 既存ファイルの一括統一は
git add --renormalize .してコミット - シェルスクリプトの
bad interpreter: ^MはCRLFが原因。LFに変換すれば直る
1. 何が起きるか / What breaks
| 症状 / Symptom | 原因 / Cause |
|---|---|
| 1文字も変えていないのにdiffが全行差分になる | エディタが保存時に改行コードを変換した |
bad interpreter: /bin/bash^M | CRLFのシェルスクリプト。shebang行末の\rがパス扱いされる |
ESLintの linebreak-style で大量エラー | ルールはLF想定、ファイルがCRLF(またはその逆) |
| Dockerにコピーしたスクリプトだけ動かない | Windowsで編集したCRLFファイルをLinuxコンテナで実行 |
| ファイルのハッシュ値が環境で変わる | 改行1バイト差でもハッシュは別物になる |
「同じに見えるのに違う」状態の確認には差分チェッカー、\r がどこにあるかの特定にはUnicode Inspectorが使えます (どちらもブラウザ内で完結し、コードを外部送信しません)。
git add 時に warning: CRLF will be replaced by LF と出ても、これはエラーではなく 正常な警告です。リポジトリ側(インデックス)はLFになりますが、ローカルの作業ツリー側のファイルは そのまま残ることがあります。
2. 現在の改行コードを確認する / How to check
- VS Code: 右下ステータスバーに「LF」「CRLF」と常時表示。クリックで変換可能
- Git:
git ls-files --eolでリポジトリ内/作業ツリーの改行を一覧表示。 出力はi/lf w/crlf attr/text=auto file.txtの形式で、i=インデックス(リポジトリ側)、w=作業ツリー側、attr=適用中の属性を表す - コマンド:
file script.sh(「with CRLF line terminators」と出る)、cat -Aなら行末に^M$
3. Gitでの統一方法 / Normalizing with Git
推奨: リポジトリに .gitattributes を置く。全員の個人設定に関係なく同じ挙動になります。
Gitの改行変換は「作業ツリー→インデックス(ステージング領域)」の間で行われます。.gitattributesやcore.autocrlfが制御しているのは主にコミットされる側(インデックス)の改行で、作業ツリー上のファイルの見た目は 自動では変わらないことがあります。「設定したのにエディタ上はまだCRLFのまま」に見えるのはこのためです。
# .gitattributes
# テキストファイルはコミット時にLFへ正規化(チェックアウトはOS依存)
* text=auto
# 常にLFでチェックアウトしたいもの(シェルスクリプト等)
*.sh text eol=lf
# 常にCRLFが必要なもの(バッチファイル)
*.bat text eol=crlf
# バイナリは変換しない
*.png binaryeol=lf / eol=crlf はチェックアウト時(作業ツリーに戻す時)の改行を固定する指定です。text=auto だけではコミット側(インデックス)がLFになるだけで、ローカルのファイル自体は 元の改行のままのことがあります。
追加したら既存ファイルを一括で正規化します。
git add --renormalize .
git commit -m "normalize line endings"個人設定の core.autocrlf を使う場合の挙動は次のとおりです。
| 設定 / Setting | コミット時 / On commit | チェックアウト時 / On checkout | 想定 / For |
|---|---|---|---|
true | LFに変換 | CRLFに変換 | Windows(CRLF前提のツールを使う) |
input | LFに変換 | 変換しない | Mac/Linux、WindowsでもLF統一なら可 |
false(既定) | 変換しない | 変換しない | .gitattributesで管理する場合 |
4. エディタ側の統一 / Editor configuration
# .editorconfig (主要エディタが標準対応)
root = true
[*]
end_of_line = lf
[*.bat]
end_of_line = crlfVS Codeなら "files.eol": "\n" でも新規ファイルをLFにできますが、 チームで共有できる .editorconfig の方が確実です。
5. English summary
LF (0x0A) is the Unix and Git-internal standard; CRLF (0x0D 0x0A) is the Windows standard. Mixed endings cause whole-file diffs, ESLint linebreak-style noise, differing hashes, and the classicbad interpreter: /bin/bash^M failure when a CRLF script runs on Linux. Check the current state with the VS Code status bar or git ls-files --eol. The robust fix is a committed .gitattributes with * text=auto (plus eol=lf for shell scripts), followed by git add --renormalize .. Per-usercore.autocrlf works but depends on every member configuring it correctly, so prefer the repository-level approach.
よくある質問 / FAQ
- 既存リポジトリの改行コードを一括で統一するには?
- .gitattributes に「* text=auto」を追加してから git add --renormalize . を実行し、コミットします。作業ツリーのファイルは次回チェックアウト時に揃います。
- core.autocrlf は true と input どちらにすべき?
- 個人設定に依存させず .gitattributes をリポジトリに置くのが現在の推奨です。個人設定だけで運用する場合、Windowsはtrue(またはinput)、Mac/Linuxはinputが定番です。
- Why does my shell script fail with 'bad interpreter ^M'?
- The script has CRLF line endings, so the kernel sees the shebang as '/bin/bash\r' which does not exist. Convert the file to LF (e.g. in your editor's status bar, or with dos2unix) and configure Git so it stays LF.
- git addで「warning: CRLF will be replaced by LF」と出るけど大丈夫?
- これはエラーではなく正常な警告です。.gitattributesやcore.autocrlfでLF正規化を設定した状態でCRLFのファイルをステージすると表示されます。コミットされる側(リポジトリ)はLFになりますが、ローカルの作業ツリー側のファイルはそのまま残ることがあります。想定通りの動作なので無視して問題ありません。
関連ツール / Related tools
- Diff Checker - 改行・空白差を含む差分の可視化
- Unicode Inspector - \r などの不可視文字を特定
- Hex Converter - 0x0D 0x0A をバイト列で確認