Sau 6 tháng làm việc với codebase có hơn 3.000 commit từ nhiều người, mình nhận ra git log mặc định gần như vô dụng. Scroll qua vài trăm dòng để tìm commit của đồng nghiệp từ tuần trước — không ai có thời gian làm vậy. Bài này mình chia sẻ những option dùng hàng ngày trên production, không phải danh sách đầy đủ từ docs.
Vấn đề với git log mặc định
Chạy git log không argument sẽ ra một đống commit theo thứ tự thời gian ngược. Format mặc định chiếm 5–6 dòng mỗi commit, thông tin không cô đọng, và không có cách nào thấy được nhánh nào đang merge vào đâu.
Ba hướng tiếp cận phổ biến khi muốn khai thác lịch sử commit:
- GUI tools như GitKraken, Sourcetree — trực quan nhưng không dùng được trong terminal, không tích hợp được vào script
- GitHub/GitLab UI — tiện nhưng phụ thuộc internet, không xem được local branch chưa push
- git log với options — chạy được mọi nơi, scriptable, nhanh hơn
Mình đã thử cả ba. Quay về terminal vì một lý do cụ thể: cần viết script phân tích commit hàng tuần để báo cáo tiến độ team. Chỉ có git log làm được điều đó mà không cần cài thêm gì.
Lọc commit theo tác giả
Option mình dùng nhiều nhất — đặc biệt trong sprint review khi cần xem work của một thành viên cụ thể:
# Lọc theo tên hoặc email
git log --author="Nguyen Van A"
git log --author="[email protected]"
# Regex cũng được — tìm tất cả người tên Nguyen
git log --author="Nguyen"
# Kết hợp: commit của mình trong 2 tuần qua
git log --author="$(git config user.name)" --since="2 weeks ago"
--author match theo regex, không phải exact string. Nếu team có người tên “An” và “Anh”, query --author="An" sẽ bắt cả hai. Dùng email hoặc thêm anchor ^An$ để chính xác hơn.
Lọc theo thời gian
Git hiểu nhiều format khác nhau — từ ISO date đến tiếng Anh tự nhiên. Cả hai đều chạy được:
# Relative time
git log --since="3 days ago"
git log --after="1 week ago"
git log --until="yesterday"
git log --before="2024-01-01"
# Khoảng thời gian cụ thể
git log --since="2024-06-01" --until="2024-06-30"
# Xem commit tuần này của toàn team
git log --since="monday" --format="%h %an %s"
--since và --after là alias của nhau. Tương tự --until và --before. Mình hay dùng cặp --since/--until vì đọc xuôi hơn khi kết hợp hai cái trong một lệnh.
Lọc theo nội dung commit và file
Có hai cách tìm — khác nhau tùy vào thứ cần tìm.
Tìm theo commit message
# --grep: tìm trong commit message
git log --grep="fix" --grep="bug" # OR (mặc định)
git log --grep="fix" --grep="auth" --all-match # AND
# Case-insensitive
git log --grep="hotfix" -i
# Tìm commit liên quan đến feature login
git log --grep="login\|auth\|authentication" -i --format="%h %s"
Tìm theo nội dung thay đổi trong code
# -S: tìm commit thêm hoặc xóa string này (pickaxe)
git log -S "password_hash"
git log -S "def calculate_tax"
# -G: tìm theo regex trong diff
git log -G "api_key.*=.*['\"]" --all
# Tìm xem ai đã xóa function này
git log -S "def send_notification" --patch
-S tìm commit mà số lần xuất hiện của string thay đổi (thêm hoặc bớt). -G tìm commit có diff chứa regex đó. Khi cần truy vết xem ai đã remove một function, -S chính xác hơn — nó chỉ báo commit thực sự làm thay đổi số lần xuất hiện, không phải mọi commit có dòng đó trong diff.
Lọc theo file hoặc thư mục
# Commit chỉ động vào file cụ thể
git log -- src/auth.py
git log -- "*.sql" # wildcard cần quote
# Commit trong một thư mục
git log -- src/api/
# Kết hợp với các filter khác
git log --since="1 month ago" --author="Anh" -- migrations/
# Xem thay đổi thực tế trong file đó qua từng commit
git log -p -- config/settings.py
Dấu -- trước path để git phân biệt đây là file/folder, không phải branch name. Bỏ đi thường vẫn chạy được — nhưng khi tên file trùng với tên branch thì lỗi ngay, không báo trước.
Trực quan hóa nhánh với –graph và –pretty
Đây là phần xử lý vấn đề mình gặp nhiều nhất: nhìn vào output của git log mà vẫn không hiểu nhánh nào merge vào đâu.
Cơ bản với –graph
# Graph đơn giản
git log --graph --oneline --decorate
# Xem tất cả nhánh
git log --graph --oneline --decorate --all
Output trông như thế này:
* a3f2c1d (HEAD -> main) fix: auth token expiry
* b1e9f8a Merge pull request #42 from feature/login
|\
| * c7d4e23 feat: implement JWT refresh
| * 9a1b5f0 feat: login endpoint
|/
* 4f8c2d1 refactor: extract user service
Custom format với –pretty
Format mặc định quá dài. Đây là cái mình đang dùng hàng ngày:
# Format ngắn gọn với màu
git log --graph --pretty=format:"%C(yellow)%h%Creset %C(cyan)%an%Creset %C(green)(%ar)%Creset %s" --all
# Format đầy đủ hơn cho report
git log --pretty=format:"%H|%an|%ae|%ad|%s" --date=short
Các placeholder hay dùng trong --pretty=format::
%h— short hash,%H— full hash%an— author name,%ae— author email%ar— relative date (“3 days ago”),%ad— absolute date%s— commit message subject%C(color)— set color,%Creset— reset color
Alias để không phải gõ mãi
Ba cái này mình đều có trong ~/.gitconfig từ lâu:
# Thêm vào ~/.gitconfig
git config --global alias.lg "log --graph --pretty=format:'%C(yellow)%h%Creset -%C(auto)%d%Creset %s %C(green)(%ar) %C(cyan)<%an>%Creset' --all"
git config --global alias.ll "log --oneline --decorate --all --graph"
git config --global alias.lw "log --pretty=format:'%C(yellow)%h%Creset %s %C(green)(%ar)%Creset' --date=relative"
# Sau đó chỉ cần
git lg
git ll
Phân tích tiến trình dự án thực tế
Team mình có 8 người. Mỗi thứ Sáu, script này chạy tự động để tổng hợp sprint report:
#!/bin/bash
# weekly-report.sh
echo "=== Sprint Report: $(date +'%Y-%m-%d') ==="
echo ""
echo "--- Commit count by author ---"
git log --since="1 week ago" --format="%an" | sort | uniq -c | sort -rn
echo ""
echo "--- Files changed most ---"
git log --since="1 week ago" --name-only --format="" | sort | uniq -c | sort -rn | head -10
echo ""
echo "--- Commit timeline ---"
git log --since="1 week ago" --format="%ad %an: %s" --date=format:"%a %H:%M" --reverse
Phần “Files changed most” hữu ích hơn mình nghĩ. File nào bị động vào nhiều nhất thường là nơi đang có vấn đề — hoặc đang có hai người làm song song mà chưa ai biết. Từ khi có report này, merge conflict trong team giảm rõ rệt: mọi người check xem nhau đang làm ở đâu trước khi bắt đầu task mới.
Kết hợp các filter: Ví dụ thực tế
# Tìm commit của mình trong tháng 6, chỉ file Python, có liên quan đến database
git log \
--author="$(git config user.name)" \
--since="2024-06-01" --until="2024-06-30" \
--grep="db\|database\|migration" -i \
-- "*.py" \
--oneline
# Debug: xem tất cả thay đổi vào một function trong 3 tháng qua
git log -G "def process_payment" --since="3 months ago" --patch -- payments/
# Audit: ai đã commit thẳng vào main mà không qua PR
git log main --no-merges --since="1 month ago" --format="%h %an %s"
Khi nào nên dùng gì
Tóm lại từ kinh nghiệm thực tế — không phải lý thuyết:
- Cần debug nhanh:
git log --oneline --graph --all— thấy toàn bộ cây nhánh trong 2 giây - Tìm ai đổi file gì:
git log --author --since -- path/to/file - Truy vết bug:
git log -S "suspicious_function" --patch— xem đúng chỗ code thay đổi - Báo cáo sprint:
git log --format --sincepipe vàosort | uniq -c - Review PR trước khi merge:
git log main..feature-branch --oneline
GUI tool vẫn có chỗ khi cần giải thích cho người mới hoặc xem diff từng dòng trực quan. Còn khi cần lọc theo người, thời gian, file, nội dung — tất cả cùng lúc — terminal nhanh hơn và không cần click.

