Bạn nhớ tên một feature flag nhưng không nhớ commit message hoặc tác giả đã sửa nó. Tìm kiếm nội dung thay đổi có thể hữu ích hơn việc tìm theo tiêu đề commit. Git có hai lựa chọn dễ bị nhầm: -S và -G.
Bài dùng một repository tạm, không cần remote. Fixture được kiểm tra bằng Git 2.54.0, đối chiếu tài liệu ngày 28/10/2026. Các lệnh log chỉ đọc lịch sử; phần tạo ví dụ bên dưới chỉ ghi vào thư mục mới do mktemp tạo.
1. Khác nhau nằm ở điều kiện chọn commit
-S tìm thay đổi làm đổi số lần xuất hiện của một chuỗi trong file. Nếu một dòng chứa flag bị sửa nhưng số lần xuất hiện của từ flag vẫn là một, commit đó có thể không được chọn.
-G tìm dòng được thêm hoặc xóa trong patch khớp một biểu thức chính quy. Nó phù hợp khi bạn nhớ một mẫu dòng đã thay đổi, kể cả số lần xuất hiện của token không đổi.
Đừng hiểu -G là tìm biểu thức trong mọi phiên bản file còn -S là tìm commit message. Cả hai đang chọn theo thay đổi nội dung; muốn tìm message thì dùng cơ chế tìm message riêng.
2. Tạo lịch sử có một thay đổi giữ nguyên số lần xuất hiện
Chạy trong cùng một phiên Bash hoặc zsh để giữ các biến demo_dir và base:
demo_dir="$(mktemp -d)"
git -C "$demo_dir" init -q
git -C "$demo_dir" config user.name Demo
git -C "$demo_dir" config user.email [email protected]
git -C "$demo_dir" config commit.gpgsign false
printf 'enabled = flag\n' > "$demo_dir/settings.txt"
git -C "$demo_dir" add settings.txt
git -C "$demo_dir" commit -qm base
base="$(git -C "$demo_dir" rev-parse HEAD)"
printf 'enabled = !flag\n' > "$demo_dir/settings.txt"
git -C "$demo_dir" add settings.txt
git -C "$demo_dir" commit -qm invert
printf 'enabled = false\n' > "$demo_dir/settings.txt"
git -C "$demo_dir" add settings.txt
git -C "$demo_dir" commit -qm remove
File settings.txt là dữ liệu giả để tìm lịch sử, không phải cấu hình đang được ứng dụng nào thực thi. Commit invert đổi cách viết của dòng nhưng vẫn chứa một từ flag. Commit remove làm số lần xuất hiện giảm từ một xuống không.
Các lệnh config chỉ áp dụng trong repository tạm. Chúng không thay đổi danh tính Git global hoặc cấu hình của dự án bạn đang làm.
3. Chạy hai phép tìm trên cùng khoảng commit
git -C "$demo_dir" log --format=%s -S'flag' "$base"..HEAD -- settings.txt
git -C "$demo_dir" log --format=%s -G'flag' "$base"..HEAD -- settings.txt
Lệnh đầu in remove. Lệnh sau in remove rồi invert, theo thứ tự lịch sử mặc định từ mới về cũ. Khoảng base..HEAD loại commit base ra khỏi phần đang xét, nên bạn không thấy lần thêm flag đầu tiên ở ví dụ này.
Khi muốn xem patch thay vì chỉ commit message, thêm -p:
git -C "$demo_dir" log -p -G'flag' "$base"..HEAD -- settings.txt
Hãy đọc cả dòng xóa và dòng thêm. Token có thể xuất hiện ở phía trước thay đổi nhưng không còn trong phiên bản hiện tại; đó chính là lý do tìm bằng log khác với chỉ tìm trong working tree.
4. Chọn phạm vi trước khi mở rộng kết quả
Trong dự án thật, thay flag bằng chuỗi hoặc mẫu bạn cần tìm và chỉ rõ đường dẫn sau --. Dấu này tách revision/options khỏi pathspec, giúp câu lệnh rõ nghĩa hơn khi tên file giống một ref hoặc tham số.
Theo mặc định, Git tìm lịch sử có thể đi tới từ ref đang xét. --all mở rộng sang các ref local đang có; nó không tự tải mọi branch đã tồn tại ở remote hoặc phục hồi ref đã bị xóa. Nếu clone đang nông, lịch sử được tìm cũng có thể chưa đủ.
-S mặc định dùng chuỗi; khi thêm --pickaxe-regex, cách hiểu pattern của nó đổi sang biểu thức chính quy. -G vốn đã dùng regex. Giữ pattern trong dấu nháy đơn khi muốn shell không diễn giải các ký tự đặc biệt trước Git.
Lỗi thường gặp và cách kiểm tra
Nếu -S không thấy một commit bạn biết có sửa dòng, kiểm tra số lần token xuất hiện ở hai phía. Ví dụ invert cho thấy “dòng thay đổi” và “số lần token thay đổi” là hai điều kiện khác nhau.
Nếu -G cho quá nhiều kết quả, thu hẹp mẫu dòng, khoảng revision và đường dẫn. Đừng đổi pattern liên tục mà quên đang tìm trên nhánh nào. Khi đã có commit nghi vấn, đọc patch và bối cảnh trước khi kết luận đó là nguồn gây lỗi.
Giới hạn của phép tìm
Kết quả chỉ nói commit đáp ứng điều kiện tìm nội dung, chưa chứng minh nó gây ra bug hoặc là người đầu tiên quyết định nghiệp vụ. Đổi tên file, lịch sử merge hoặc chuỗi xuất hiện ở nhiều vị trí có thể cần điều tra tiếp.
Bắt đầu bằng một token rõ ràng, so hai phía của diff rồi mở rộng phạm vi có lý do. Bạn sẽ có một đường đi kiểm chứng được thay vì đoán commit từ những message không mô tả hết thay đổi.


