1. Vấn đề thực tế khi làm việc với repository phức tạp
Dự án monorepo công ty mình từng phình to hơn 15 microservices với hàng chục thư mục lồng nhau. Quản lý file khi đó thực sự thành ác mộng. Có hôm, một bạn junior tá hỏa vì file .env.staging vô tình lọt vào commit rồi đẩy thẳng lên remote repo. Ai cũng đinh ninh file này đã được ignore từ trước.
Lần khác, một file icon mới tại packages/ui/assets/icons/logo.svg lại không hiện khi gõ git status. Cả team loay hoay không rõ nguyên nhân. Để kịp tiến độ, anh em thường chọn cách nhanh nhất: gõ git add -f để ép Git nhận file.
Hậu quả sau đó rất phiền toái. Dung lượng repo tăng vọt, xung đột dấu ngắt dòng (CRLF/LF) giữa Windows và macOS nổ ra liên miên trên từng pull request. Việc cấu hình sai ignore và attributes vẫn là bẫy ngầm khó phát hiện nếu chỉ nhìn bằng mắt thường.
2. Vì sao Git không bỏ qua file như bạn mong đợi?
Git không chỉ đọc duy nhất một file .gitignore ở thư mục gốc. Khi xác định một file có bị bỏ qua hay gán thuộc tính hay không, Git duyệt qua nhiều tầng ưu tiên:
- File
.gitignorecục bộ: Các file nằm rải rác trong từng thư mục con sẽ ghi đè quy tắc của thư mục cha. - File cấu hình riêng của repo: File
.git/info/excludechỉ có hiệu lực trên máy cá nhân và không được commit lên remote. - File cấu hình toàn cục: File global ignore được định nghĩa qua biến
core.excludesFiletrong~/.gitconfig. - Quy tắc phủ định (Negation
!): Nếu thư mục cha đã bị ignore hoàn toàn (ví dụdist/), Git bỏ qua toàn bộ thư mục đó. Quy tắc phủ định bên trong như!dist/bundle.jssẽ hoàn toàn vô tác dụng.
Cơ chế của .gitattributes cũng tương tự. Thiết lập chuyển đổi dòng (eol=lf), filter Git LFS hay diff driver đều bị ghi đè theo cấp bậc thư mục. Khi repo có hàng chục file cấu hình lồng nhau, tra cứu thủ công là bất khả thi.
3. Các thói quen xử lý sai lầm thường gặp
Cách 1: Lùng sục thủ công bằng Ctrl + F hoặc grep
Mỗi khi file bị ẩn, dev thường mở file .gitignore ở root rồi nhấn Ctrl + F. Tìm không thấy, họ lại lần mò vào từng thư mục con để đọc tiếp.
Điểm yếu: Cách này tốn thời gian và dễ bỏ sót các mẫu glob phức tạp như **/*.log hay build/*/temp. Bạn cũng hoàn toàn mù tịt trước các quy tắc đến từ global config trên máy cá nhân.
Cách 2: Chữa cháy bằng git add -f
Khi cần commit gấp mà Git ngó lơ file, nhiều bạn tiện tay gõ luôn:
git add -f src/services/mailer/templates/welcome.html
Điểm yếu: Lệnh force chỉ giải quyết phần ngọn. Rule sai trong cấu hình vẫn nằm nguyên đó. Đồng nghiệp khác khi pull code về và sửa tiếp file này vẫn sẽ bị ignore. Nguy hiểm hơn, thói quen này rất dễ làm lọt các file chứa secret, credential nhạy cảm lên repo.
Cách 3: Sử dụng git check-ignore và git check-attr
Git tích hợp sẵn hai công cụ chuyên dụng: git check-ignore và git check-attr. Chúng hoạt động như một công cụ debug, chỉ ra chính xác dòng nào trong file cấu hình nào đang chi phối file của bạn.
4. Quy trình debug chuẩn xác trong thực tế
Từ khi đưa hai lệnh này vào checklist xử lý sự cố của team, mọi khúc mắc về ignore và line-ending đều được giải quyết trong vài giây.
Debug quy tắc loại trừ với git check-ignore
Cú pháp hiệu quả nhất là thêm cờ -v (verbose). Git sẽ in ra chi tiết: File cấu hình : Số dòng kích hoạt : Mẫu quy tắc (pattern).
# Kiểm tra file local.json bị ignore bởi dòng nào
git check-ignore -v config/environments/local.json
Kết quả trả về trên terminal:
.gitignore:14:local.* config/environments/local.json
Output hiển thị rõ ràng: dòng 14 trong file .gitignore gốc với rule local.* chính là nguyên nhân.
Muốn kiểm tra nhiều file cùng lúc, hãy thêm cờ --non-matching (hoặc -n) để xem cả những file không bị ignore:
# Kiểm tra danh sách file
git check-ignore -v -n src/index.ts .env.local docs/setup.pdf
Output mẫu:
:: src/index.ts
.gitignore:3:.env* .env.local
packages/docs/.gitignore:2:*.pdf docs/setup.pdf
Ký hiệu :: ở dòng đầu tiên cho biết file src/index.ts hoàn toàn bình thường, không khớp với bất kỳ rule ignore nào.
Xử lý bẫy Negation (!) thường gặp
Một tình huống rất phổ biến: bạn muốn bỏ qua thư mục logs/ nhưng cần giữ lại file logs/important.log.
# Cấu hình sai trong .gitignore:
logs/
!logs/important.log
File important.log vẫn không xuất hiện khi chạy git status. Hãy soi lại bằng git check-ignore:
git check-ignore -v logs/important.log
# Trả về: .gitignore:1:logs/ logs/important.log
Cách sửa chuẩn: Thay vì ignore cả thư mục logs/, bạn chỉ ignore nội dung bên trong để Git vẫn duyệt thư mục này:
# Cấu hình đúng trong .gitignore:
logs/*
!logs/important.log
Kiểm tra thuộc tính file với git check-attr
Trên môi trường cross-platform hoặc khi sử dụng Git LFS, file .gitattributes chịu trách nhiệm định dạng text/binary và quy tắc chuyển đổi CRLF/LF.
Để liệt kê toàn bộ thuộc tính đang áp dụng cho một file:
git check-attr -a src/scripts/deploy.sh
Kết quả hiển thị:
src/scripts/deploy.sh: text: set
src/scripts/deploy.sh: eol: lf
src/scripts/deploy.sh: diff: unspecified
Để kiểm tra xem file thiết kế Photoshop dung lượng 50MB đã ăn cấu hình Git LFS hay chưa:
git check-attr filter diff merge assets/banner.psd
Nếu terminal trả về filter: lfs, cấu hình đã chuẩn. Nếu là unspecified, file .gitattributes đang thiếu rule cho định dạng *.psd.
Bảng lệnh bỏ túi cần nhớ
git check-ignore -v <path>: Tìm chính xác file và số dòng đang ignore target.git check-ignore -v -n <paths...>: Kiểm tra trạng thái ignore của nhiều file cùng lúc.git check-attr -a <path>: Xem toàn bộ thuộc tính EOL, diff, LFS gán lên file.
Gặp file bị ẩn hoặc sai format dòng, đừng vội gõ git add -f. Chạy thử hai lệnh trên, bạn sẽ bắt đúng bệnh và sửa tận gốc vấn đề.

