Giao diện
Git Debugging: Bisect & Blame 🔍
ROLE: HPN (Investigative Engineering).
AUDIENCE: Engineers debugging production issues and investigating code history.
Bugs xuất hiện. Đó là điều chắc chắn. Điều quan trọng là bạn tìm ra chúng nhanh như thế nào. Module này trang bị cho bạn hai vũ khí mạnh nhất để điều tra lịch sử Git: Bisect (Binary Search) và Blame (Accountability).
🎯 Mục tiêu
Sau module này, bạn sẽ:
- Tìm commit gây bug trong 500 commits chỉ với ~9 bước (O(log N))
- Tự động hóa bisect với test scripts
- Dùng
git blameđể hiểu context thay đổi, không chỉ tìm "ai viết" - Master các flags nâng cao để ignore noise
🔬 Git Bisect - Binary Search for Bugs
The Problem
"Tuần trước code còn chạy. Hôm nay bug. Có 500 commits giữa hai thời điểm. Tìm commit nào gây bug?"
Cách thủ công: Check từng commit → O(N) → Mất cả ngày
Cách thông minh: Binary Search → O(log N) → ~9 bước cho 500 commits
log₂(500) ≈ 9 stepsHow Bisect Works
Mỗi bước loại bỏ 50% commits. Sau 9-10 bước, bạn tìm được commit gây bug.
Basic Bisect Workflow
bash
# Step 1: Bắt đầu bisect session
git bisect start
# Step 2: Mark commit hiện tại là BAD (có bug)
git bisect bad
# Step 3: Mark commit cũ là GOOD (chưa có bug)
git bisect good v1.0.0 # hoặc commit SHA
# Git checkout commit giữa, bạn test...
# Nếu có bug:
git bisect bad
# Nếu không có bug:
git bisect good
# Lặp lại cho đến khi Git thông báo:
# "abc123def is the first bad commit"
# Step 4: Kết thúc và quay về branch
git bisect resetExample Session
bash
$ git bisect start
$ git bisect bad HEAD
$ git bisect good v2.0.0
Bisecting: 256 revisions left to test after this (roughly 8 steps)
[abc123] feat: add user authentication
# Test code... có bug!
$ git bisect bad
Bisecting: 128 revisions left to test after this (roughly 7 steps)
[def456] refactor: database connection
# Test code... không bug
$ git bisect good
Bisecting: 64 revisions left to test after this (roughly 6 steps)
...
# Sau ~8 steps:
abc789def is the first bad commit
commit abc789def
Author: Developer <dev@example.com>
Date: Mon Dec 18 2023
feat: add caching layer
src/cache.py | 42 ++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)⚡ Automated Bisect - The Power Move
Thay vì test thủ công, viết script và để Git tự chạy:
bash
# Tạo test script
cat > test.sh << 'EOF'
#!/bin/bash
# Exit 0 = GOOD, Exit 1-124 = BAD, Exit 125 = SKIP
# Run your test
npm test 2>&1 | grep -q "PASS"
EOF
chmod +x test.sh
# Chạy bisect tự động
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test.sh
# Ngồi uống cà phê, Git tự tìm commit ☕Exit Codes for bisect run
| Exit Code | Meaning | Git Action |
|---|---|---|
0 | GOOD - No bug | Mark good, continue |
1-124 | BAD - Bug found | Mark bad, continue |
125 | SKIP - Can't test | Skip this commit |
126-127 | Error | Abort bisect |
Advanced: Skip Untestable Commits
bash
# Nếu commit không build được, skip nó
git bisect skip
# Hoặc trong script:
#!/bin/bash
if ! make build 2>/dev/null; then
exit 125 # Skip
fi
./run_tests.shReal-World Script Examples
Python Project
bash
#!/bin/bash
# test_bisect.sh
# Install dependencies (nếu cần)
pip install -r requirements.txt -q 2>/dev/null || exit 125
# Run specific test
python -m pytest tests/test_auth.py -x -q 2>&1
# pytest exit code: 0 = pass, 1+ = failNode.js Project
bash
#!/bin/bash
# test_bisect.sh
npm install --silent 2>/dev/null || exit 125
npm test -- --grep "login feature" 2>&1Build Verification
bash
#!/bin/bash
# Tìm commit gây build failure
make clean && make build 2>&1
# Exit 0 = builds, Exit 1+ = broken🎯 Bisect Tips
PRO TIP: Bisect với Terms tùy chỉnh
Thay vì good/bad, dùng terms phù hợp hơn:
bash
git bisect start --term-old=working --term-new=broken
git bisect broken HEAD
git bisect working v1.0.0CẢNH BÁO: Đừng quên reset!
Luôn chạy git bisect reset khi xong. Nếu không, bạn sẽ ở trạng thái DETACHED HEAD.
📋 Git Blame - Beyond "Who Did This"
The Typical Use
bash
# Ai viết dòng này?
git blame src/auth.pyOutput:
a1b2c3d4 (Alice 2023-12-01 10:00:00 +0700 1) def authenticate(user):
e5f6g7h8 (Bob 2023-12-15 14:30:00 +0700 2) if not user.is_valid():
i9j0k1l2 (Alice 2023-12-01 10:00:00 +0700 3) return False
m3n4o5p6 (Charlie 2023-12-20 09:15:00 +0700 4) return check_password(user)Beyond "Who" - Understanding "Why"
Blame không chỉ để tìm người đổ lỗi. Nó giúp hiểu context của thay đổi.
bash
# Xem commit message của từng dòng
git blame -c src/auth.py
# Xem full commit info
git blame -l src/auth.py
# Show commit SHA đầy đủ
git log -1 --format="%B" <sha-from-blame>Blame Specific Lines
bash
# Chỉ blame dòng 10-20
git blame -L 10,20 src/auth.py
# Blame từ dòng 10 đến hết file
git blame -L 10, src/auth.py
# Blame function cụ thể (regex)
git blame -L '/def authenticate/,/^def /' src/auth.py🔇 Ignoring Noise
Problem: Whitespace/Formatting Changes
Ai đó chạy prettier và format lại toàn bộ file. Giờ blame hiển thị họ là "author" của mọi dòng.
bash
# Ignore whitespace changes
git blame -w src/auth.py
# Ignore moved/copied lines trong cùng file
git blame -M src/auth.py
# Ignore moved/copied từ file khác
git blame -C src/auth.py
# Combo: ignore tất cả noise
git blame -w -M -C src/auth.pyUsing .git-blame-ignore-revs
Tốt hơn: Tạo file list các commits cần ignore (formatting, mass refactors):
bash
# Tạo file .git-blame-ignore-revs
cat > .git-blame-ignore-revs << EOF
# Prettier formatting
abc123def456789
# ESLint auto-fix
def789ghi012345
EOF
# Dùng file này khi blame
git blame --ignore-revs-file .git-blame-ignore-revs src/auth.py
# Hoặc config globally cho repo
git config blame.ignoreRevsFile .git-blame-ignore-revsTEAM BEST PRACTICE
Commit file .git-blame-ignore-revs vào repo. Mọi người trong team sẽ có blame sạch.
Blame Through Renames
bash
# Theo dõi file qua renames
git blame --follow old_name.pyShow Original Commit (Pre-move)
bash
# Hiển thị commit gốc, không phải commit move code
git blame -C -C -C src/auth.pyBa -C flags:
-C: Detect moves/copies trong commit này-C -C: ...và trong commit tạo file-C -C -C: ...và trong bất kỳ commit nào
🔗 Combining Bisect + Blame
Workflow thực tế:
bash
# 1. Dùng bisect tìm commit gây bug
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test.sh
# Found: abc123
# 2. Xem commit đó thay đổi gì
git show abc123
# 3. Blame dòng cụ thể để hiểu context
git blame -L 42,50 src/cache.py
# 4. Xem history của dòng đó
git log -p -L 42,50:src/cache.py📊 Quick Reference
Bisect Commands
| Command | Purpose |
|---|---|
git bisect start | Bắt đầu session |
git bisect bad [ref] | Mark commit có bug |
git bisect good [ref] | Mark commit không bug |
git bisect skip | Skip commit không test được |
git bisect run <script> | Auto-bisect với script |
git bisect log | Xem log session |
git bisect reset | Kết thúc, về branch gốc |
Blame Commands
| Command | Purpose |
|---|---|
git blame <file> | Basic blame |
git blame -L 10,20 <file> | Blame specific lines |
git blame -w <file> | Ignore whitespace |
git blame -M <file> | Detect moved lines |
git blame -C <file> | Detect copied lines |
git blame --ignore-revs-file <file> | Ignore listed commits |
💡 Key Takeaways
HPN'S INSIGHT
"Bisect + automated tests = Debugging superpower. Bạn có thể tìm bug trong 10,000 commits trong vài phút."
- Bisect là O(log N): 500 commits = ~9 bước, không phải 500
- Automate bisect: Viết test script, để Git chạy
- Blame không phải để đổ lỗi: Hiểu context, không phải tìm người
- Ignore noise: Use
-w -M -Cvà.git-blame-ignore-revs - Combine tools: Bisect tìm commit → Blame hiểu context
SENIOR ENGINEER PERSPECTIVE
Junior devs scroll qua history thủ công. Senior devs dùng bisect run. Khác biệt? Một người mất 4 giờ, một người mất 5 phút.