devAlice
← Multi-OS

Git 改行コード — Mac/Linux と Windows の CRLF 地獄を終わらせる

`.gitattributes` 1枚でどこでも改行コードを統一する。core.autocrlf の罠と正しいやり方。

同じリポジトリを Mac/Linux と Windows で共有していれば、ほぼ確実にこれに遭遇する — CRLF vs LF。何も変えていないのに PR の diff が「1000行変更」に膨れ上がり、シェルスクリプトが \r: command not found で壊れ、Python が SyntaxError: invalid character を吐く。

このガイドは .gitattributes を使ってすべての OS で同じ改行コードを保証する正しい方法だ。一度設定してしまえば、二度と気にしなくて済む。

TL;DR

  1. リポルートに .gitattributes を置き * text=auto eol=lf と書く
  2. core.autocrlf をオフにする.gitattributes がどうせ上書きする
  3. Windows シェルスクリプトには LF を強制(*.sh text eol=lf
  4. Windows バッチファイルには CRLF を強制(*.bat text eol=crlf
  5. 統一後は git add --renormalize . を実行して既存ファイルを揃える

前提条件

  • Git 2.10+(.gitattributeseol= をサポート)
  • Mac/Win ユーザーが同時に push するリポジトリ

1. 問題 — CRLF がなくならない理由

1.1 OS デフォルトの改行コード

OS改行コード歴史
Unix · macOS · LinuxLF (\n、0x0A)Unix 1970年〜
WindowsCRLF (\r\n、0x0D 0x0A)DOS 1980年〜
Classic Mac OS 9CR (\r)1984〜2001年

1.2 git の自動変換 — core.autocrlf

チェックアウト時コミット時
true(Windows デフォルト)LF → CRLFCRLF → LF
input(Unix 推奨)なしCRLF → LF
falseなしなし

問題は、ユーザーごとに設定がバラバラで、新しいマシンではデフォルトのまま使われ、サイレントな変換が「何も変えていないのに diff が出た」という事態を引き起こすことだ。

1.3 正しいやり方は .gitattributes

リポジトリ内に置くことでチーム全員に同じルールを強制できる。core.autocrlf の個人設定を上書きする。


2. .gitattributes ベースライン — 5分

リポルートの .gitattributes

# デフォルト — すべてのテキストファイルを LF で保存し、テキスト/バイナリを自動判定
* text=auto eol=lf
 
# 明示的なテキスト — LF 強制
*.c          text eol=lf
*.cc         text eol=lf
*.cpp        text eol=lf
*.h          text eol=lf
*.hpp        text eol=lf
*.cs         text eol=lf
*.go         text eol=lf
*.java       text eol=lf
*.kt         text eol=lf
*.py         text eol=lf
*.rb         text eol=lf
*.rs         text eol=lf
*.swift      text eol=lf
*.ts         text eol=lf
*.tsx        text eol=lf
*.js         text eol=lf
*.jsx        text eol=lf
*.mjs        text eol=lf
*.cjs        text eol=lf
*.json       text eol=lf
*.jsonc      text eol=lf
*.yml        text eol=lf
*.yaml       text eol=lf
*.toml       text eol=lf
*.md         text eol=lf
*.mdx        text eol=lf
*.txt        text eol=lf
*.html       text eol=lf
*.css        text eol=lf
*.scss       text eol=lf
*.svg        text eol=lf
*.xml        text eol=lf
*.sql        text eol=lf
 
# シェルスクリプト — LF(CRLF で壊れる)
*.sh         text eol=lf
*.bash       text eol=lf
*.zsh        text eol=lf
*.fish       text eol=lf
Dockerfile*  text eol=lf
Makefile*    text eol=lf
 
# Windows 専用 — CRLF
*.bat        text eol=crlf
*.cmd        text eol=crlf
*.ps1        text eol=crlf
*.psm1       text eol=crlf
 
# バイナリ — 変換なし
*.png        binary
*.jpg        binary
*.jpeg       binary
*.gif        binary
*.ico        binary
*.webp       binary
*.avif       binary
*.pdf        binary
*.zip        binary
*.gz         binary
*.tar        binary
*.7z         binary
*.exe        binary
*.dll        binary
*.so         binary
*.dylib      binary
*.woff       binary
*.woff2      binary
*.ttf        binary
*.otf        binary
*.mp3        binary
*.mp4        binary
*.mov        binary
 
# diff を静かにする — テキストだが diff は無意味
*.lock       text eol=lf -diff
pnpm-lock.yaml text eol=lf -diff
package-lock.json text eol=lf -diff
yarn.lock    text eol=lf -diff
Cargo.lock   text eol=lf -diff

⚠️ PowerShell ファイル(*.ps1)は CRLF が必要。Windows PowerShell は LF のみの ps1 を拒否することがある。


3. 既存リポジトリへの適用 — 5分

.gitattributes を追加してコミットし、すでにずれている改行コードを揃え直す

3.1 renormalize

# リポルートで
git add .gitattributes
git commit -m "feat: add .gitattributes baseline"
 
# .gitattributes に従って全ファイルを揃え直す
git add --renormalize .
git status   # 何が変わったか確認
git commit -m "chore: renormalize line endings"

--renormalize は作業ツリーには触れず、インデックスだけを書き換える。他のメンバーは pull 時に自動的に揃う。

3.2 大規模リポジトリ / アクティブなコラボレーション

--renormalize は巨大な PR を生む。事前に調整しよう:

  • 時間枠を設ける(「X 以降は push を止める」)
  • renormalize をマージして全員が一度 git pull する
  • またはフィーチャーブランチで git rebase origin/main して吸収する

3.3 小規模リポジトリ / 個人

1つの PR としてそのままマージする。


4. ユーザーのグローバル設定 — core.autocrlf を鎮める — 1分

.gitattributes があるリポジトリでは core.autocrlf は実質的に意味をなさない。ただし .gitattributes がないレガシー・外部リポジトリでは依然として重要になる。推奨設定:

# macOS / Linux
git config --global core.autocrlf input
# チェックアウト時に変換なし、コミット時に CRLF → LF
 
# Windows
git config --global core.autocrlf input
# Windows でも input を推奨 — ファイルは常に LF でコミットされる。他者の CRLF も正規化される。
 
# または .gitattributes だけを信頼する
git config --global core.autocrlf false

Windows でも input を推奨する理由:OS デフォルトに左右されず、常に LF でコミットされるため一貫性が保てる。

core.eol

git config --global core.eol lf

チェックアウト時のデフォルト改行コードを指定する。.gitattributeseol= 設定が優先される。


5. エディタ設定 — IDE を揃える

VS Code(.vscode/settings.json またはユーザー設定):

{
  "files.eol": "\n",
  "files.insertFinalNewline": true,
  "files.trimTrailingWhitespace": true
}

JetBrains:Settings → Editor → Code Style → Line separator → Unix and macOS (\n)

Vim:

" ~/.vimrc
set fileformats=unix,dos
set fileformat=unix

6. 検証 — 本当に LF になっているか?

6.1 単一ファイル

# macOS/Linux
file scripts/build.sh
# ASCII text  ← OK
file scripts/build.sh | grep -q CRLF && echo has CRLF
 
# または
od -c scripts/build.sh | head -3
# 行末が \n のみ。\r \n が見えたら CRLF が残っている。

6.2 リポ全体

# CRLF を含むファイルを検索
git grep --cached -lI $'\r' -- ':!*.bat' ':!*.cmd' ':!*.ps1'

-I はバイナリを除外。意図的な CRLF ファイル(ps1、bat)を除外する。

6.3 CI ゲートを追加する

GitHub Actions:

- name: Check no CRLF in LF files
  run: |
    crlf=$(git grep --cached -lI $'\r' -- ':!*.bat' ':!*.cmd' ':!*.ps1' || true)
    if [ -n "$crlf" ]; then
      echo "CRLF found in LF-expected files:"
      echo "$crlf"
      exit 1
    fi

7. よくある落とし穴と修正

7.1 .sh が Windows で ^M: command not found になる

CRLF のシェルスクリプトがコミットされてしまっている。応急処置:

dos2unix scripts/build.sh
# または
sed -i 's/\r$//' scripts/build.sh

根本的な修正:.gitattributes*.sh text eol=lf を追加して git add --renormalize を実行する。

7.2 Python の SyntaxError: invalid character

CRLF + UTF-8 BOM の .py ファイル。.gitattributes で LF を強制 + エディタで BOM を削除する。

sed -i '1s/^\xEF\xBB\xBF//' file.py

7.3 .gitattributes が実際に適用されていない

  • .gitattributes がルートではなくサブディレクトリにある — そのサブディレクトリのみに適用される点に注意
  • ファイルが renormalize されていない — 既存の改行コードが残り続ける(git add --renormalize . を実行する)

7.4 IDE が CRLF で再保存する

.editorconfig を追加する:

# .editorconfig(リポルート)
root = true
 
[*]
end_of_line = lf
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
 
[*.{bat,cmd,ps1}]
end_of_line = crlf

VS Code、JetBrains、Vim、Sublime など多くのエディタが .editorconfig を自動で読む。

7.5 Windows エディタが自動的に BOM を追加する

PowerShell の Out-File はデフォルトで UTF-16 BOM を付加する。UTF-8 を強制するには:

$content | Out-File "file.txt" -Encoding utf8 -NoNewline
# または PowerShell 7+
$content | Out-File "file.txt" -Encoding utf8NoBOM

8. 既存リポジトリを修正する PR チェックリスト

  • .gitattributes ベースラインを追加(§2)
  • .editorconfig を追加(§7.4)
  • git add --renormalize . + コミット
  • CI CRLF チェックを追加(§6.3)
  • チームに通知 — 「pull 後に git config --global core.autocrlf input を確認してください」
  • README に1行 — 「このリポジトリは LF に統一している。.gitattributes を参照してください。」

次のステップ

参考資料

更新履歴

  • 2026-05-12 — 初稿(devAlice M2 シード展開)