파일명의 대소문자만 변경했을 때 Git이 변경사항을 감지하지 못하는 경우가 있다. 원인과 해결 방법을 정리한다.
CSS 파일명이 Main.css로 되어 있어 소문자 main.css로 바꾸려고 했다.
에디터나 탐색기에서 이름만 바꾼 뒤 Git 상태를 확인했는데, 변경사항 목록에 아무것도 잡히지 않았다.
Git은 기본적으로 파일명 대소문자 차이를 "변경"으로 보지 않는 설정이 적용되어 있다.
즉, Main.css와 main.css를 같은 파일로 취급해서 변경사항이 없다고 판단한다.
운영 서버에서는 대소문자가 다르면 완전히 다른 파일로 취급한다. 예를 들어 실제 파일이 Main.css인데 HTML에서 <link href="main.css">로 참조하면 로컬에서는 정상 로드되지만 서버에서는 파일을 찾지 못한다.
| 참조 경로 | 로컬 | 서버 |
|---|---|---|
main.css | 정상 | 404 |
Main.css | 정상 | 정상 |
실제 파일명이
Main.css인 경우 기준
로컬에서는 잘 작동하던 페이지가 배포 후 CSS/JS가 깨지는 현상이 생긴다. 로컬에서 재현이 안 되기 때문에 원인을 찾기 어렵다.
git mv 명령어 사용파일명 대소문자만 바꿀 때는 에디터나 탐색기에서 바꾸지 말고, 터미널에서 git mv 명령어로 변경한다.
git mv Main.css main.css
git commit -m "Main.css 파일명 소문자로 변경"
git push
이렇게 하면 Git이 파일명 변경을 정상적으로 인식한다.
git mv 실행 시 에러가 나는 경우다음과 같은 에러가 발생할 수 있다.
fatal: renaming 'Main.css' failed: Invalid argument
이는 일부 환경에서 대소문자만 다른 두 파일명을 같은 파일로 인식해, 자기 자신으로의 이름 변경을 거부하기 때문이다. 이때는 임시 파일명을 거쳐 두 단계로 변경한다.
# 1단계: 임시 파일명으로 변경
git mv Main.css temp-main.css
git commit -m "임시 파일명 변경"
# 2단계: 최종 파일명으로 변경
git mv temp-main.css main.css
git commit -m "파일명 소문자로 변경"
git push
이 상태에서는 git status에 아무 변경사항도 잡히지 않는다. Git이 파일명 변경을 감지하지 못했기 때문이다.
되돌리거나 별도 작업을 할 필요 없이, 그 상태 그대로 아래 명령어를 실행해본다.
git mv Main.css main.css
Git 내부 기록은 여전히 Main.css이므로 위 명령어가 그대로 처리되는 경우가 많다.
다만 환경에 따라서는 디스크상으로 이미 main.css로 바뀌어 있어 Main.css를 찾지 못한다는 에러가 발생할 수 있다. 이때는 고민하지 말고 곧바로 임시 파일명 2단계 방식으로 진행한다. 이 경우 디스크에 이미 존재하는 이름(main.css)부터 시작한다.
git mv main.css temp-main.css
git commit -m "임시 파일명 변경"
git mv temp-main.css main.css
git commit -m "파일명 소문자로 변경"
core.ignorecase 설정에 대해Git에는 파일명 대소문자 구분 여부를 제어하는 core.ignorecase 옵션이 있다.
git config core.ignorecase false
이 값을 false로 바꾸면 에디터나 탐색기에서 이름만 바꿔도 Git이 변경사항으로 인식한다.
다만 기본값이 true로 되어 있는 데는 이유가 있다. 파일시스템 자체가 대소문자를 구분하지 않는 환경에서 이 설정을 강제로 켜면, 추적되지 않는 파일명 충돌이 발생하거나 동일 파일이 두 번 등록되는 등 예상치 못한 문제가 생길 수 있다.
따라서 팀 표준으로 권장하기보다는, 동작 원리를 이해한 사람이 필요할 때 선택적으로 쓰는 옵션 정도로 인지하는 편이 안전하다. 적용한다면 팀 전체가 사전 합의 후 동일하게 설정해야 한다.
main-banner.css)git mv를 사용한다git status로 파일명 변경이 정상적으로 잡혔는지 반드시 확인한다git mv 명령어를 사용한다.git mv가 실패하면 임시 파일명을 거쳐 두 단계로 나누어 변경한다.core.ignorecase 설정은 동작 원리를 이해한 뒤 팀 합의를 거쳐 신중히 적용한다.