Giao diện
Staging Area & Atomic Commits
Khi mới học Git, nhiều người nghĩ git add chỉ là bước thủ tục trước git commit. Đó là cách hiểu khiến lịch sử dự án nhanh chóng biến thành mớ hỗn độn: commit vừa có feature, vừa có debug log, vừa có sửa tài liệu, vừa lẫn file rác local. Bài này sửa đúng tư duy đó: Staging Area không phải bãi trung chuyển, mà là bộ lọc để bạn chốt đúng thay đổi cần chốt.
Vấn đề thật sự mà bài này giải quyết là gì?
Trong công việc thực tế, bạn rất hiếm khi sửa đúng một thứ duy nhất rồi commit ngay. Thường thì workflow sẽ giống thế này:
- Bạn sửa API validation cho endpoint đăng ký.
- Trong lúc debug, bạn thêm vài
console.log()hoặcprint(). - Bạn tiện tay cập nhật luôn tài liệu API.
- IDE sinh thêm file local cache hoặc log.
Nếu bạn dùng kiểu phản xạ git add . && git commit -m "update stuff", bạn vừa tạo ra một commit:
- khó review
- khó revert
- khó cherry-pick
- khó tìm bug sau này
Atomic commit giải bài toán đó: mỗi commit chỉ nên đại diện cho một ý định kỹ thuật rõ ràng.
Mental model: Working Directory → Staging Area → Commit History
Đây là mô hình bạn phải nhìn thấy trong đầu mỗi lần chuẩn bị commit:
text
┌──────────────────────┐ git add / git add -p ┌──────────────────────┐ git commit ┌──────────────────────┐
│ Working Directory │ ───────────────────────────▶ │ Staging Area │ ─────────────────▶ │ Commit History │
│ Nơi bạn đang sửa │ │ Nơi chọn đúng phần │ │ Lịch sử đã chốt │
│ Có thể rất lộn xộn │ ◀──── git restore / edit ──── │ sẽ đi vào commit │ │ để review / revert │
└──────────────────────┘ └──────────────────────┘ └──────────────────────┘Điểm quan trọng:
- Working Directory có thể bừa bộn tạm thời.
- Staging Area phải có chủ đích.
- Commit History phải sạch, dễ đọc, dễ phục hồi.
Nếu bạn bỏ qua Staging Area như một bước suy nghĩ, bạn đang biến lịch sử commit thành ảnh chụp của sự lộn xộn thay vì nhật ký kỹ thuật có cấu trúc.
TIP
Nếu cần ôn lại trạng thái file và cách đọc output, xem thêm Add & Commit (The Workflow) và Status & Log (Inspection).
Atomic commit là gì?
Atomic commit là commit mà:
- chỉ làm một việc
- có thể mô tả bằng một câu rõ ràng
- nếu cần rollback thì rollback một ý định, không phá hỏng thứ khác
Ví dụ xấu
text
feat: update auth flowNhưng bên trong lại chứa:
- sửa API login
- thêm 6 dòng debug log
- cập nhật README
- đổi format vài file không liên quan
Đây không phải atomic commit. Đây là "túi nilon tổng hợp".
Ví dụ tốt
text
fix(auth): validate refresh token rotation
docs(api): document new refresh token responseHai commit riêng biệt này tốt hơn vì:
- reviewer đọc dễ hơn
- CI fail thì khoanh vùng nhanh hơn
- docs có thể merge riêng
- hotfix có thể cherry-pick riêng nếu cần
Safe staging habits — thói quen staging an toàn
Đây là phần quan trọng nhất của bài.
1) Luôn kiểm tra trước khi add
Trước khi staged bất kỳ thứ gì, hãy nhìn trạng thái hiện tại:
bash
git status
git diffgit status trả lời câu hỏi: Git đang thấy gì?git diff trả lời câu hỏi: Mình vừa sửa chính xác cái gì?
2) Đừng mặc định dùng git add .
git add . không sai trong mọi tình huống. Nó chỉ nguy hiểm khi bạn dùng nó như phản xạ.
Không nên dùng git add . khi:
- working tree đang chứa nhiều thay đổi không liên quan
- bạn vừa debug bằng log tạm
- có file untracked mà bạn chưa chắc nên commit
- IDE hoặc local tooling sinh file rác
- bạn muốn tách code change và docs change thành 2 commit
Đây chính là câu trả lời cho câu hỏi bắt buộc số (2): khi nào không nên dùng lệnh obvious nhất?
→ Không dùng git add . khi working tree đang lẫn nhiều ý định kỹ thuật hoặc có nguy cơ cuốn theo file rác.
3) Stage theo file khi ý định đã rõ
Ví dụ bạn muốn commit riêng phần API:
bash
git add src/api/auth.ts src/api/token-service.ts
git diff --cached
git commit -m "fix(auth): validate refresh token rotation"Sau đó mới commit docs:
bash
git add docs/api/authentication.md
git diff --cached
git commit -m "docs(api): document refresh token response"4) Dùng partial staging khi một file chứa nhiều loại thay đổi
Đây là kỹ năng giúp bạn thật sự làm chủ Staging Area:
bash
git add -pgit add -p cho phép bạn stage theo từng hunk thay vì cả file. Cực kỳ hữu ích khi:
- cùng một file vừa có logic thật vừa có debug log
- bạn refactor một phần, nhưng chưa muốn commit phần còn lại
- bạn sửa bug và dọn code trong cùng một file nhưng muốn tách commit
5) Luôn xem lại phần đã staged trước khi commit
bash
git diff --cachedNếu bạn chưa có thói quen này, hãy tạo nó ngay. Đây là lớp kiểm tra cuối cùng trước khi thay đổi đi vào lịch sử.
6) Giữ junk files ra khỏi commit
Các file sau thường không nên vào repo:
- log debug local
.env- local database dump
- file build tạm
- file cache từ IDE
Nếu git status cho thấy các file kiểu này, đừng staged cho tới khi bạn chắc chúng là một phần hợp lệ của thay đổi. Với secret và file nhạy cảm, đọc thêm Git Security & Secret Handling.
Tình huống thực tế #1: trộn feature code với debug logs
Bạn đang sửa bug timeout ở service gọi payment provider:
src/payment/retry-service.tscó fix logic thật- cùng file đó có thêm 4 dòng
console.log("retry payload", payload)
Phản xạ nguy hiểm:
bash
git add .
git commit -m "fix(payment): handle retry timeout"Vấn đề:
- commit trông có vẻ sạch nhưng thực ra mang theo debug noise
- reviewer phải tự đoán dòng nào là business logic, dòng nào là rác tạm
- nếu log lộ dữ liệu nhạy cảm, bạn vừa tạo risk không đáng có
Workflow đúng:
bash
git add -p src/payment/retry-service.ts
git diff --cached
git commit -m "fix(payment): handle retry timeout"Sau đó:
- hoặc xóa debug log trước commit kế tiếp
- hoặc giữ chúng ở working directory cho tới khi debug xong
Tình huống thực tế #2: tách API changes và docs changes
Bạn thêm field tokenExpiresAt vào response của endpoint login và cũng sửa tài liệu API.
Nếu bạn commit chung một cục:
- PR khó review theo từng concern
- docs team hoặc backend team khó cherry-pick riêng
- nếu code bị rollback nhưng docs không rollback theo, lịch sử rất khó hiểu
Workflow tốt hơn:
- stage và commit code backend trước
- stage và commit docs sau
bash
git add src/api/auth-controller.ts src/api/contracts/login-response.ts
git diff --cached
git commit -m "feat(auth): add tokenExpiresAt to login response"
git add docs/api/authentication.md
git diff --cached
git commit -m "docs(auth): document tokenExpiresAt in login response"Đây là giá trị cốt lõi của atomic commits: một thay đổi lớn trong đầu bạn được tách thành các đơn vị review được trong mắt người khác.
Câu hỏi bắt buộc (1): chính xác bài này giải quyết vấn đề gì?
Nó giải quyết ba vấn đề rất thực tế:
- Lịch sử commit lộn xộn — vì bạn commit mọi thứ đang có thay vì commit đúng ý định.
- Code review tốn thời gian — vì reviewer phải lọc tay đâu là thay đổi chính, đâu là noise.
- Khó phục hồi khi có sự cố — vì một commit chứa quá nhiều thứ không liên quan, nên revert hoặc cherry-pick đều đau đớn.
Nói ngắn gọn: Staging Area + atomic commits biến Git từ công cụ lưu snapshot thành công cụ tổ chức thay đổi.
Câu hỏi bắt buộc (2): khi nào bạn không nên dùng lệnh obvious?
Lệnh obvious ở đây thường là:
bash
git add .Không nên dùng khi:
- bạn chưa đọc
git status - bạn chưa kiểm tra diff
- working tree chứa nhiều luồng công việc
- có file local/junk/untracked chưa được xác minh
- bạn cần một commit đủ sạch để review, revert, hoặc cherry-pick
Nếu mọi thay đổi trong working tree đều thực sự thuộc cùng một mục tiêu, git add . có thể chấp nhận được. Nhưng trong môi trường kỹ thuật thực tế, điều đó ít xảy ra hơn bạn tưởng.
Câu hỏi bắt buộc (3): nếu dùng sai thì phục hồi thế nào?
Trường hợp A — stage nhầm nhưng chưa commit
Đây là case dễ nhất:
bash
git diff --cached
git restore --staged <file>Nếu lỡ stage nhiều thứ:
bash
git restore --staged .Sau đó stage lại cho đúng bằng file cụ thể hoặc git add -p.
Trường hợp B — đã commit local nhưng chưa push
Bạn vẫn còn cửa sửa lịch sử an toàn:
bash
git reset --soft HEAD~1
git restore --staged .
git status
git add -p
git commit -m "..."--soft giữ nguyên thay đổi trong working tree, chỉ lùi commit pointer để bạn đóng gói lại cho sạch hơn. Sau đó bỏ toàn bộ index hiện tại khỏi staging area và stage lại đúng phần cần giữ.
Trường hợp C — đã push lên branch shared
Lúc này đừng hoảng và đừng rewrite shared history bừa bãi. Hướng xử lý an toàn hơn thường là:
- tạo commit follow-up để xóa junk
- hoặc revert nếu commit sai gây rủi ro thật sự
- phối hợp với team nếu có secret hoặc dữ liệu nhạy cảm
Phục hồi sâu hơn nằm ở các bài sau:
Một workflow staging an toàn mà bạn nên tập thành phản xạ
text
1. git status
2. git diff
3. Chọn đúng phần cần commit
4. git add <file> hoặc git add -p
5. git diff --cached
6. git commit -m "một ý định rõ ràng"Nếu bạn chỉ nhớ một điều từ bài này, hãy nhớ câu sau:
Working Directory có thể bừa bộn, nhưng commit history thì không được phép bừa bộn.
🧠 Quiz
Câu 1: Staging Area hữu ích nhất ở điểm nào?
- [ ] A. Nó tự động tối ưu performance của Git repository
- [x] B. Nó cho phép chọn đúng phần thay đổi sẽ đi vào commit tiếp theo
- [ ] C. Nó thay thế hoàn toàn cho
git diff - [ ] D. Nó giúp push code nhanh hơn
💡 Giải thích: Staging Area là lớp chọn lọc giữa Working Directory và Commit History. Giá trị của nó nằm ở khả năng đóng gói thay đổi theo ý định, không phải ở tốc độ.
Câu 2: Khi nào không nên dùng git add .?
- [ ] A. Khi repo đang clean
- [x] B. Khi working tree chứa feature code, debug logs, docs update, hoặc file rác lẫn với nhau
- [ ] C. Khi chỉ có đúng một file thay đổi
- [ ] D. Khi bạn đang ở branch feature
💡 Giải thích:
git add .nguy hiểm nhất khi nó kéo vào staging những thứ không cùng một mục tiêu kỹ thuật.
Câu 3: Nếu bạn stage nhầm file nhưng chưa commit, bước phục hồi an toàn là gì?
- [ ] A.
git reset --hard - [x] B.
git restore --staged <file>rồi stage lại cho đúng - [ ] C.
git push --force - [ ] D. Xóa cả branch và làm lại từ đầu
💡 Giải thích: Khi mới stage nhầm, vấn đề còn rất rẻ để sửa. Chỉ cần bỏ file khỏi staging area và chọn lại đúng phần cần commit.