개발 도구 ·

문자 인코딩과 줄바꿈 때문에 파일 전체가 바뀌어 보이는 이유

먼저 답부터

문자 인코딩은 글자를 저장할 바이트 규칙이고 줄바꿈은 한 줄의 끝을 표시하는 보이지 않는 기호입니다. 파일을 다른 인코딩으로 읽으면 글자가 깨지고, LF와 CRLF가 한꺼번에 바뀌면 내용은 같아도 모든 줄이 수정된 것처럼 보일 수 있습니다. 변환 전에 편집기 표시, Git 속성, 실제 변경 범위를 먼저 확인해야 합니다.

문자 인코딩과 줄바꿈 때문에 파일 전체가 바뀌어 보이는 이유 대표 이미지

문서에서 한 문장만 고쳤는데 Git이 모든 줄을 변경으로 표시하거나, 멀쩡하던 한글이 물음표와 네모로 보일 때가 있습니다. 이때 내용을 다시 쓰기 전에 파일을 읽는 규칙과 줄 끝을 표시하는 방식이 달라졌는지부터 확인해야 합니다.

같은 악보를 두 사람이 읽는 장면을 생각해 보세요. 음표에 어떤 소리를 연결하는 표가 다르면 같은 종이를 보고도 다른 소리를 내고, 마디를 나누는 표식이 다르면 곡 전체의 줄이 어긋나 보입니다. 텍스트 파일에서도 문자 인코딩과 줄바꿈은 내용 자체가 아니라 내용을 읽고 나누는 약속입니다.

문자 인코딩은 글자를 바이트로 옮기는 표다

컴퓨터는 파일 안에 글자 모양을 그대로 넣지 않고 바이트라는 작은 숫자 단위로 저장합니다. 문자 인코딩은 어떤 글자를 어떤 바이트 순서로 저장하고 다시 읽을지 정한 규칙입니다. 같은 바이트를 저장할 때와 다른 규칙으로 읽으면 원래 글자를 복원하지 못해 깨진 문자가 나타날 수 있습니다.

UTF-8은 Unicode 문자를 바이트로 표현하는 널리 쓰이는 방식입니다. Unicode 공식 안내는 새 웹 문서에서 UTF-8을 사용하고 같은 인코딩을 일관되게 적용할 것을 권합니다. 그렇다고 오래된 파일을 이름만 보고 무조건 UTF-8로 다시 저장하면 안 됩니다. 실제 원본 인코딩과 사용하는 프로그램의 요구를 먼저 확인해야 되돌릴 수 없는 손상을 피할 수 있습니다.

줄바꿈은 화면에 잘 보이지 않는 줄 끝 표시다

Enter를 누르면 눈에는 다음 줄로 이동한 것만 보이지만 파일에는 줄의 끝을 알리는 값이 들어갑니다. LF는 줄을 내린다는 한 가지 값을 쓰고, CRLF는 줄의 처음으로 돌아간 뒤 다음 줄로 내린다는 두 값을 함께 씁니다. macOS와 Linux의 텍스트 파일에서는 LF가 흔하고 Windows 도구에서는 CRLF를 자주 만납니다.

둘 중 하나가 모든 상황에서 무조건 옳은 것은 아닙니다. 실행 환경이나 파일 종류가 특정 방식을 요구할 수 있습니다. Git 공식 문서는 저장소의 텍스트 파일을 보통 LF로 보관하면서 작업 폴더에서는 운영체제와 속성 설정에 맞춰 줄바꿈을 바꿀 수 있다고 설명합니다. 팀 저장소에서는 개인 편집기 기본값보다 저장소에 기록된 규칙이 우선입니다.

내용이 같아도 모든 줄이 바뀐 것처럼 보일 수 있다

한 줄 끝이 LF에서 CRLF로 바뀌면 Git은 그 줄의 보이지 않는 값도 변경으로 비교합니다. 편집기가 파일을 열고 저장하는 과정에서 모든 줄의 끝을 바꾸면, 글자는 거의 그대로인데도 파일 전체가 삭제되고 다시 추가된 것처럼 보일 수 있습니다.

글자 깨짐과 전체 줄 변경은 원인이 다릅니다. 글자 깨짐은 저장된 바이트를 다른 문자 인코딩으로 읽었을 가능성을 먼저 보고, 전체 줄 변경은 LF와 CRLF가 섞였거나 일괄 변환됐는지 확인합니다. 둘이 동시에 생길 수도 있으므로 화면만 보고 한 가지 원인으로 단정하지 않습니다.

편집기 표시와 Git 상태를 읽기부터 한다

대부분의 코드 편집기는 현재 파일의 인코딩과 줄바꿈 방식을 화면 아래 상태 영역에 보여 줍니다. 먼저 그 표시를 메모하고, 저장 전후에 값이 달라졌는지 확인합니다. Git에서는 현재 변경 파일 수와 diff를 읽되, 다른 사람의 작업이 섞인 저장소에서 변환이나 일괄 추가 명령부터 실행하지 않습니다.

다음은 실행 명령이 아니라 확인 결과를 남기는 예시입니다.

파일: notes.md
편집기 인코딩: UTF-8
편집기 줄바꿈: LF
Git 표시: 한 문장만 변경
다음 행동: 변환하지 않고 저장소 규칙 확인

이 기록에서 인코딩, 줄바꿈, 실제 내용 변경을 서로 다른 칸에 두는 것이 중요합니다. 파일이 깨져 보인다는 이유로 바로 저장하면 잘못 읽힌 상태가 새 내용으로 덮일 수 있으므로, 원본을 닫고 복사본이나 버전 기록에서 다시 확인할 수 있어야 합니다.

저장소 규칙은 파일 종류마다 다르게 정할 수 있다

GitHub 공식 문서는 저장소 루트의 .gitattributes 파일로 텍스트와 바이너리 파일, 줄바꿈 규칙을 지정할 수 있다고 안내합니다. text=auto는 Git이 텍스트 여부를 판단하도록 하고, eol=lf와 eol=crlf는 작업 폴더에서 사용할 줄바꿈을 파일 종류별로 정합니다. 이미지 같은 바이너리 파일은 텍스트 변환 대상이 아니라고 표시할 수 있습니다.

하지만 기존 저장소에 새 규칙을 추가하면 많은 파일이 한꺼번에 변경으로 나타날 수 있습니다. 규칙을 바꾸는 일과 실제 기능 코드를 고치는 일을 같은 커밋에 섞지 마세요. 저장소 관리자와 기대하는 파일 종류를 합의하고, 깨끗한 작업 트리와 별도 검토에서 예상 파일만 바뀌는지 확인한 뒤 적용해야 합니다.

자동 변환보다 원본 보존과 변경 범위가 먼저다

GitHub 안내에는 줄바꿈 규칙을 바꾼 뒤 파일을 다시 정규화하는 절차가 있지만, 이는 저장소 전체에 큰 변경을 만들 수 있습니다. 의미를 모르는 상태에서 git add --renormalize . 같은 명령을 복사해 실행하지 마세요. 현재 폴더, 대상 파일, 기존 사용자 변경, 백업이나 복구 커밋을 설명할 수 없으면 멈추는 것이 안전합니다.

인코딩 변환도 같은 원칙을 따릅니다. 원본을 별도 이름으로 보존하고 작은 복사본에서 한글, 이모지, 따옴표가 그대로 왕복되는지 확인합니다. 비밀키, 결제 설정, 고객 정보가 든 파일은 온라인 변환기에 올리지 않습니다. 운영 설정이나 데이터 파일을 실습 대상으로 쓰지 말고, 삭제나 덮어쓰기가 포함된 도구는 결과 경로와 복구 방법을 확인하기 전에는 실행하지 않습니다.

오늘 바로 해볼 작은 실습

공개 저장소의 작은 Markdown 파일이나 직접 만든 연습용 텍스트 파일 하나를 10분 동안 읽기만 합니다.

  1. 편집기에서 파일을 열고 현재 인코딩 표시를 적습니다.
  2. 줄바꿈 표시가 LF인지 CRLF인지 적습니다.
  3. 저장소에 .gitattributes가 있는지 파일 목록에서만 확인합니다.
  4. 있다면 연습 파일의 확장자와 맞는 규칙이 있는지 읽습니다.
  5. Git 변경 화면에서 실제 문장과 줄 끝 변경이 구분되는지 봅니다.
  6. 인코딩 다시 열기, 줄바꿈 변환, 전체 정규화 기능은 실행하지 않습니다.
  7. 파일 이름, 현재 규칙, 예상 변경, 복구 위치를 한 줄씩 기록합니다.
  8. 비밀키와 개인정보와 결제 설정이 없는 연습 파일인지 다시 확인합니다.

실습의 목표는 파일을 즉시 고치는 것이 아니라 무엇이 달라졌는지 말로 나누는 것입니다. 문자 인코딩, 줄바꿈, 실제 내용 변경을 각각 설명할 수 있으면 첫 진단이 끝납니다. 그다음에만 저장소 규칙과 원본 보존 방법을 확인하고 가장 작은 파일부터 별도 변경으로 검증하세요.

확인한 자료

함께 읽기

  • Git 커밋과 브랜치를 게임 저장 지점처럼 이해하기

    Git 커밋은 지금 파일 상태를 다시 찾을 수 있게 남기는 저장 지점이고, 브랜치는 원본 흐름을 건드리지 않고 다른 수정을 시험하는 별도 길입니다. AI에게 코드를 맡기기 전에 커밋을 만들면 문제가 생겨도 바뀐 부분을 비교하고 안전하게 되돌리기 쉽습니다.

  • 파일 경로를 집 주소처럼 읽고 터미널에서 길을 잃지 않는 법

    파일은 내용을 담은 문서이고 폴더는 파일을 묶는 공간입니다. 절대경로는 출발점부터 적은 전체 주소, 상대경로는 현재 폴더를 기준으로 적은 길 안내입니다. 터미널에서는 먼저 `pwd`로 현재 위치를 확인한 뒤 `ls`로 목록만 읽으면 엉뚱한 곳을 바꾸는 실수를 줄일 수 있습니다.

  • npm 패키지와 의존성을 장보기 목록처럼 읽는 법

    npm 패키지는 프로젝트에서 다시 쓸 수 있게 묶은 코드이고, 의존성은 내 프로젝트가 작동하려고 기대는 패키지입니다. package.json은 필요한 이름과 허용 버전을 적은 목록이며 package-lock.json은 실제 설치된 전체 버전을 기록하므로 둘을 함께 보관해야 같은 환경을 재현하기 쉽습니다.