Vấn đề
Bạn đổi tên utils.js thành Utils.js — chỉ một chữ hoa. Chạy git status: không có gì. Git coi như chưa có chuyện gì xảy ra.
Ở máy local, mọi thứ chạy bình thường. Rồi bạn push lên server CI chạy Linux và build thất bại — các import bị lỗi vì server tìm Utils.js nhưng repo vẫn còn utils.js. Đây là lỗi kinh điển: ẩn ở local, bùng phát trên production.
Tại sao điều này xảy ra
Windows (NTFS) và macOS (HFS+/APFS ở cấu hình mặc định) sử dụng filesystem không phân biệt chữ hoa/thường. Đối với hệ điều hành, file.txt và File.txt là cùng một file. Vì Git dựa vào filesystem để phát hiện thay đổi, nó không bao giờ nhận ra sự khác biệt.
Còn một tùy chọn Git config liên quan: core.ignoreCase. Trên Windows và macOS, Git tự động đặt giá trị này thành true khi cài đặt. Điều đó là có chủ đích — nó ngăn các false positive trên filesystem không phân biệt chữ hoa/thường. Nhưng cũng có nghĩa là Git sẽ bỏ qua hoàn toàn các lần đổi tên theo chữ hoa/thường thực sự.
Linux thì khác. Filesystem của nó phân biệt chữ hoa/thường, nên file.txt và File.txt là hai file hoàn toàn khác nhau. Khi code chạy trên Linux — server, Docker container, GitHub Actions — nó tìm đúng tên file trong repo. Nếu Git chưa bao giờ theo dõi việc đổi tên, tên cũ vẫn còn đó và các tham chiếu bị hỏng.
Cách sửa 1: Dùng git mv với tên tạm thời (Khuyến nghị)
Đổi tên qua một tên trung gian tạm thời. Cách này đánh lừa Git ghi lại hai lần đổi tên riêng biệt thay vì một lần đổi tên vô hình.
# Bước 1: Đổi sang tên tạm thời
git mv utils.js utils_temp.js
# Bước 2: Đổi từ tên tạm sang tên cuối cùng
git mv utils_temp.js Utils.js
# Bước 3: Xác nhận Git đã ghi lại
git status
Staging area bây giờ sẽ hiển thị:
Changes to be committed:
renamed: utils.js -> Utils.js
# Bước 4: Commit
git commit -m "Rename utils.js to Utils.js"
Cách sửa 2: Đặt core.ignoreCase = false và đổi tên trực tiếp
Một tùy chọn khác — chuyển Git sang chế độ phân biệt chữ hoa/thường chỉ cho thao tác này:
# Bật phân biệt chữ hoa/thường cho repo này
git config core.ignoreCase false
# Bây giờ đổi tên trực tiếp
git mv utils.js Utils.js
git status
Sau khi commit, bạn có thể giữ nguyên core.ignoreCase false hoặc đặt lại. Lưu ý: để giá trị false trên filesystem không phân biệt chữ hoa/thường đôi khi khiến Git báo các thay đổi ảo trên file không bị chỉnh sửa. Cách sửa 1 tránh hoàn toàn vấn đề này.
# Tùy chọn: khôi phục config sau khi commit
git config core.ignoreCase true
Cách sửa 3: Đã commit với tên sai chữ hoa/thường?
Nếu file đã được commit và push với tên sai, cần cập nhật trực tiếp index:
# Xóa file cũ khỏi index của Git (không xóa khỏi ổ đĩa)
git rm --cached utils.js
# Thêm file với tên mới đúng
git add Utils.js
# Commit bản sửa
git commit -m "Fix: rename utils.js to Utils.js (case correction)"
Nếu Git báo lỗi file không tồn tại, thử cách triệt để hơn — index lại toàn bộ:
# Trên macOS/Windows khi file không hiển thị thay đổi:
git rm -r --cached .
git add .
git commit -m "Fix file casing in Git index"
Cảnh báo: git rm -r --cached . bỏ stage mọi thứ rồi thêm lại. Các file thực tế của bạn không bị ảnh hưởng — lệnh này chỉ tác động đến Git index. Dù vậy, hãy chạy git status trước khi commit để kiểm tra các file không liên quan mà bạn không muốn đưa vào.
Kiểm tra: Xác nhận đã sửa thành công
Kiểm tra xem việc đổi tên có hiển thị đúng trong commit cuối không:
# Kiểm tra commit mới nhất có ghi nhận việc đổi tên
git log --oneline --name-status -1
Kết quả mong đợi:
a3f9c12 Rename utils.js to Utils.js
R100 utils.js Utils.js
R100 có nghĩa là Git đã ghi lại việc đổi tên với độ tương đồng 100%. Nếu thấy D (đã xóa) và A (đã thêm) thay vào đó thì không lý tưởng, nhưng vẫn hoạt động — file sẽ tồn tại với tên đúng trên Linux sau khi clone mới.
Push và xác nhận trên remote:
git push origin main
# Sau đó kiểm tra GitHub/GitLab — file bây giờ phải hiển thị đúng chữ hoa/thường
Phòng ngừa: Thêm Git alias cho việc đổi tên theo chữ hoa/thường
Thường xuyên đổi tên file theo chữ hoa/thường? Thêm alias này vào config toàn cục một lần và quên đi thao tác hai bước:
git config --global alias.mvcased '!f() { git mv "$1" "${1}_tmp" && git mv "${1}_tmp" "$2"; }; f'
Cách dùng:
git mvcased utils.js Utils.js
Tóm tắt nhanh
- Tình huống 1 — File chưa commit:
git mv file.txt temp.txt && git mv temp.txt File.txt - Tình huống 2 — Đã commit, chưa push: Đặt
core.ignoreCase false, dùnggit mv, rồi reset lại config - Tình huống 3 — Đã push:
git rm --cached oldname+git add newname+ commit + push - Tình huống 4 — Nhiều file bị ảnh hưởng:
git rm -r --cached . && git add .để index lại toàn bộ

