Một script chạy git diff rồi kết luận repository sạch vì không có output. Nhưng thay đổi có thể đã được stage, hoặc file mới còn untracked. Trước khi dùng kết quả làm điều kiện chạy tiếp, cần xác định hai trạng thái nào đang được so sánh.
Bài dùng Git 2.54.0, đối chiếu tài liệu ngày 01/11/2026. Fixture đã chạy trong repository tạm với cấu hình kiểm thử tách khỏi global/system config. Không thay đổi checkout hiện tại, không fetch hoặc push.
1. Quiet vẫn có kết quả qua exit status
git diff --quiet tắt output và hàm ý exit-code: 0 nghĩa không có khác biệt trong phạm vi so sánh, 1 nghĩa có khác biệt. Lỗi thực thi cần được tách khỏi kết quả “có thay đổi”.
Không thêm echo giữa command và bước đọc $?, vì command mới có thể làm mất status vừa cần dùng. Khi viết script có set -e, đặt phép kiểm tra trong điều kiện if để chủ động xử lý hai kết quả bình thường.
if git diff --quiet --no-ext-diff --; then
printf 'Khong co thay doi unstaged duoc so sanh\n'
else
diff_status=$?
if [ "$diff_status" -eq 1 ]; then
printf 'Co thay doi unstaged\n'
else
printf 'Git gap loi, ma=%s\n' "$diff_status" >&2
exit "$diff_status"
fi
fi
Đây là mẫu đọc trong repository bạn đang kiểm tra. Nó không stage, commit hoặc khôi phục file. Cụm “được so sánh” có ý nghĩa vì pathspec, tùy chọn và trạng thái index ảnh hưởng phạm vi kết quả.
Mẫu trên chỉ in phân loại: hai kết quả bình thường đều kết thúc bằng printf thành công. Nếu muốn chặn quy trình khi có thay đổi, đặt exit 1 trong nhánh đó theo chính sách gate; đừng coi thông báo đã in là mã lỗi đã được truyền ra ngoài.
2. Chọn staged hay unstaged
Mặc định, git diff so working tree với index. Thêm --cached để so index với HEAD trong tình huống repo đã có commit. Một file đã git add có thể không còn khác giữa working tree và index nhưng vẫn khác với HEAD.
Fixture sau chỉ tạo dữ liệu trong thư mục mới bằng mktemp. Hàm expect_diff xác nhận status mong đợi và dừng nếu Git trả kết quả khác.
#!/usr/bin/env bash
set -eu
demo_dir=$(mktemp -d)
git init -q --template= "$demo_dir"
git -C "$demo_dir" config user.name 'AeDev Demo'
git -C "$demo_dir" config user.email '[email protected]'
printf 'base\n' > "$demo_dir/note.txt"
git -C "$demo_dir" add note.txt
git -C "$demo_dir" -c commit.gpgsign=false commit -qm base
expect_diff() {
expected=$1
shift
if git -C "$demo_dir" diff --quiet --no-ext-diff "$@" --; then
actual=0
else
actual=$?
fi
test "$actual" -eq "$expected"
}
expect_diff 0
printf 'changed\n' >> "$demo_dir/note.txt"
expect_diff 1
expect_diff 0 --cached
git -C "$demo_dir" add note.txt
expect_diff 0
expect_diff 1 --cached
git -C "$demo_dir" -c commit.gpgsign=false commit -qm changed
printf 'scratch\n' > "$demo_dir/scratch.txt"
expect_diff 0
expect_diff 0 --cached
git -C "$demo_dir" status --porcelain=v1 --untracked-files=normal
printf 'Repo thu: %s\n' "$demo_dir"
Các kiểm tra status đã đạt. Cuối fixture, status báo scratch.txt là untracked dù hai phép diff đều trả 0. Đường dẫn repo được in để bạn có thể xem lại; script không xóa dữ liệu ở nơi khác.
3. Untracked cần được xem riêng
File chưa có trong index không tự xuất hiện trong phép diff mặc định như một thay đổi đã track. Khi mục tiêu là xác định working tree có việc gì chưa xử lý, hãy xem thêm git status với lựa chọn untracked rõ ràng.
Porcelain được thiết kế cho việc đọc bằng script. Nếu cần xử lý tên file có khoảng trắng hoặc xuống dòng, dùng dạng phân cách NUL và parser phù hợp; không tách tên file chỉ theo dấu cách. Mẫu trên chỉ in tên đơn giản, chưa cung cấp parser tổng quát.
Ignored file cũng cần chính sách riêng. Một file cache ignored có thể tồn tại mà bạn vẫn coi workspace hợp lệ; một file đầu vào bị ignore nhầm lại là lỗi. Không đồng nhất “không có output diff” với “mọi file đều đã được xem xét”.
Kiểm tra và giới hạn
Thử lần lượt file track chưa sửa, sửa chưa stage, sửa đã stage và file mới. Đưa vào script kiểm tra cả nhánh lỗi, chẳng hạn chạy ở một thư mục không phải repository. Không chuyển mọi mã khác 0 thành câu “có diff”.
Mẫu chưa xử lý toàn bộ trường hợp submodule, textconv hoặc cấu hình diff tùy biến. Trước khi đặt gate cho quy trình thật, ghi rõ gate đang kiểm tra phạm vi nào và loại file nào cần tính. Lựa chọn đúng phạm vi quan trọng hơn việc rút câu lệnh xuống ngắn nhất.

