devAlice
← Multi-OS

Git line endings — Mac/Linux와 Windows 사이 CRLF 지옥 끝내기

.gitattributes 한 파일로 모든 머신에서 같은 줄바꿈을 보장한다. core.autocrlf 함정과 정공법.

같은 저장소를 Mac/Linux와 Windows에서 같이 쓰면 거의 반드시 마주치는 문제 — CRLF vs LF. PR diff가 "한 글자도 안 바뀌었는데 1000줄 변경됨"으로 폭발하거나, 셸 스크립트가 \r: command not found로 깨지거나, 파이썬이 SyntaxError: invalid character 에러를 낸다.

이 가이드는 모든 OS에서 같은 줄바꿈을 보장하는 .gitattributes 정공법을 정리한다. 한 번 셋업하면 평생 안 본다.

TL;DR

  1. 저장소 root에 .gitattributes를 두고 * text=auto eol=lf 명시
  2. core.autocrlf꺼두는 것이 정공법 — autocrlf보다 .gitattributes가 우선
  3. Windows 셸 스크립트는 강제로 LF (*.sh text eol=lf)
  4. Windows 배치 파일은 강제로 CRLF (*.bat text eol=crlf)
  5. 한 번 통합 후 git add --renormalize .로 기존 파일 재정렬

사전 조건

  • Git 2.10+ (.gitattributes eol= 지원)
  • 저장소가 Mac/Win 사용자에 의해 동시에 push되고 있음

1. 문제 — 왜 CRLF가 사라지지 않는가

1.1 줄바꿈의 OS별 기본값

OS줄바꿈이력
Unix·macOS·LinuxLF (\n, 0x0A)Unix 1970~
WindowsCRLF (\r\n, 0x0D 0x0A)DOS 1980~
구식 Mac OS 9CR (\r)1984~2001

1.2 git의 자동 변환 옵션 — core.autocrlf

체크아웃 시커밋 시
true (Windows 기본)LF → CRLFCRLF → LF
input (Unix 권장)변환 없음CRLF → LF
false변환 없음변환 없음

문제는 — 사람마다 이 설정이 다르고, 새 머신에서 다른 값으로 깔리고, 사용자가 모르게 줄바꿈이 변환되어 "안 바꿨는데 바뀜" 사태가 발생한다.

1.3 정공법은 .gitattributes

저장소 안에 두고 모든 사람에게 같은 규칙 강제. core.autocrlf보다 우선.


2. .gitattributes 베이스라인 — 5분

저장소 root에 .gitattributes:

# Default — 모든 텍스트 파일은 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가 무의미한 파일
*.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를 추가하고 commit한 직후, 이미 잘못된 줄바꿈으로 들어가 있는 파일을 다시 정렬해야 한다.

3.1 renormalize

# 저장소 root에서
git add .gitattributes
git commit -m "feat: add .gitattributes baseline"
 
# 모든 파일을 .gitattributes 규칙에 맞춰 재정렬
git add --renormalize .
git status   # 어떤 파일이 바뀌었는지 확인
git commit -m "chore: renormalize line endings"

--renormalize는 working tree의 파일을 변경하지 않고, index만 새 규칙대로 저장. 다음 사람이 pull 받으면 자동 정렬.

3.2 큰 저장소 / 협업 중

--renormalize는 큰 PR을 만든다. 협업 중인 저장소면:

  • 사람들과 시간 조율 ("X시 이후 push 자제")
  • renormalize 머지 후 모두가 한 번 git pull
  • 또는 작업 브랜치들에서 git rebase origin/main로 자동 통합

3.3 작은 저장소 / 혼자

부담 없이 한 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로 만들었어도 LF로 정규화.
 
# 또는 .gitattributes만 신뢰
git config --global core.autocrlf false

input을 Win에서도 권장하는 이유: 본인 작업 결과가 OS 기본값에 흔들리지 않고 항상 LF.

core.eol

git config --global core.eol lf

체크아웃 시 default 줄바꿈. .gitattributeseol=이 우선.


5. 에디터 설정 — IDE도 같은 방향

VS Code (.vscode/settings.json 또는 user settings):

{
  "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 CRLF 있음
 
# 또는
od -c scripts/build.sh | head -3
# 각 줄 끝에 \n 만 보여야 함. \r \n 같이 보이면 CRLF.

6.2 저장소 전체

# CRLF가 섞인 파일 찾기
git grep --cached -lI $'\r' -- ':!*.bat' ':!*.cmd' ':!*.ps1'

-I는 바이너리 제외. ps1/bat 같은 의도적 CRLF는 제외.

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로 커밋된 셸 스크립트가 WSL/Linux에서 실행. 해결:

# 빠른 수동 변환
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

.py 파일이 CRLF + UTF-8 BOM. .gitattributes로 LF 강제 + 에디터에서 BOM 제거.

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

7.3 .gitattributes가 실제로 안 통하는 경우

  • .gitattributes가 root에 없고 하위 디렉토리에 있는 경우 — 하위 디렉토리에만 적용
  • 파일이 --renormalize 안 됐을 때 — 이미 들어간 줄바꿈은 그대로 (한 번 renormalize 필수)

7.4 IDE가 CRLF로 다시 저장

.editorconfig도 같이:

# .editorconfig (저장소 root)
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 baseline 추가 (§2)
  • .editorconfig 추가 (§7.4)
  • git add --renormalize . + commit
  • CI에 CRLF 검사 추가 (§6.3)
  • 팀에 공지 — "pull 받고 git config --global core.autocrlf input 확인"
  • README에 한 줄 — "이 저장소는 LF 통일. .gitattributes 참고"

다음 단계

참고 링크

변경 이력

  • 2026-05-12 — 초안 (devAlice M2 시드 확장)

댓글