0

Xử lý lỗi "Unstaged Changes" ảo khi dùng chung Git giữa Windows và WSL

Khi phát triển dự án microservices với hàng chục repository được lưu trữ trên phân vùng ổ đĩa Windows (ví dụ: C:\ được mount vào /mnt/c/ trong WSL), việc sử dụng song song các công cụ Git GUI trên Windows (như Fork, SourceTree, GitKraken) và WSL Terminal (Ubuntu) để chạy script tự động (Makefile, Docker) rất dễ dẫn đến xung đột trạng thái file.


1. Triệu chứng nhận biết

  • Trên ứng dụng Git GUI (Windows): Danh sách Local Changes hoàn toàn trống (working tree clean), không hề có bất kỳ chỉnh sửa nào được ghi nhận.
  • Trên WSL Terminal (Linux): Khi chạy lệnh git status hoặc kéo code hàng loạt qua make exec STATEMENT="git pull", Git báo lỗi hàng loạt file bị thay đổi (modified):
    error: cannot pull with rebase: You have unstaged changes.
    error: Please commit or stash them.
    
  • Khi kiểm tra bằng git diff: Toàn bộ nội dung file bị đánh dấu xóa đi và thêm lại y hệt nhưng xuất hiện ký tự ^M ở cuối mỗi dòng (ví dụ: +.git^M).

2. Nguyên nhân gốc rễ

Hiện tượng bất đồng bộ này xuất phát từ 2 sự khác biệt cốt lõi giữa hệ điều hành Windows và Linux khi cùng đọc một tệp tin trên ổ cứng:

Yếu tố xung đột Cơ chế trên Windows (Git GUI / Fork) Cơ chế trên Linux (WSL Ubuntu) Hệ quả
Ký tự xuống dòng (Line Endings) Mặc định sử dụng chuẩn CRLF (\r\n). Khi clone hoặc checkout bằng công cụ trên Windows, Git tự động chèn thêm ký tự \r (hiển thị là ^M trên Linux) vào cuối mỗi dòng. Mặc định sử dụng chuẩn LF (\n). Git trên WSL thấy sự xuất hiện của ký tự \r (^M) nên coi đó là thay đổi nội dung file. Toàn bộ file trong dự án bị báo modified trên WSL dù không ai sửa code.
Quyền thực thi file (File Mode) Hệ thống tệp NTFS của Windows không sử dụng cơ chế phân quyền chmod của POSIX. Git trên Windows mặc định bỏ qua quyền này. Khi mount ổ C:\ vào /mnt/c/, WSL tự động gán quyền thực thi (100755) cho toàn bộ file trên ổ Windows. Git trên WSL thấy quyền file đổi từ 100644 sang 100755 và báo thay đổi.

3. Giải pháp khắc phục triệt để

Bước 1: Đồng bộ cấu hình Git toàn cục (Global Config) trên WSL

Mở WSL Terminal và thiết lập để Git trên Linux tự động chuyển đổi ký tự xuống dòng tương thích với Windows, đồng thời bỏ qua việc kiểm tra quyền chmod:

git config --global core.autocrlf true
git config --global core.fileMode false

Bước 2: Làm sạch trạng thái ảo và cập nhật code hàng loạt

Di chuyển vào thư mục chứa Makefile quản lý các microservices và chạy lệnh khôi phục lại bộ nhớ đệm (working tree) trước khi kéo code mới:

make exec STATEMENT="git checkout -- . && git pull"

(Lưu ý: Nếu một số repository cục bộ đã bị ghi đè cấu hình fileMode = true bên trong file .git/config riêng của nó, hãy chạy lệnh make exec STATEMENT="git config core.fileMode false" để ép toàn bộ các service nhận cấu hình mới).


4. Chuẩn hóa cho toàn bộ dự án bằng .gitattributes (Khuyến nghị cho Team)

Để mọi thành viên trong nhóm không phải tự cấu hình thủ công trên từng máy mỗi khi clone dự án về, bạn nên thêm file .gitattributes vào thư mục gốc của từng repository với nội dung sau:

# Tự động chuẩn hóa line endings về LF khi đẩy lên Git server
* text=auto eol=lf

# Đảm bảo các file script Linux luôn giữ chuẩn LF kể cả khi mở trên Windows
*.sh text eol=lf
Makefile text eol=lf
Dockerfile text eol=lf

Việc cố định eol=lf ngay trong .gitattributes sẽ buộc cả ứng dụng Fork trên Windows lẫn Git trên WSL đều sử dụng chung chuẩn xuống dòng LF, loại bỏ hoàn toàn lỗi ^M từ gốc.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí