Sau Bài 10 ghép nhiều repo lại với nhau, bài này xoay quanh 2 công cụ vận hành hằng ngày ít được để ý: hooks — script tự động chạy tại các mốc cố định trong vòng đời commit, và worktree — cách checkout nhiều branch song song mà không cần clone lại repo.

1. Git Hooks: Tự Động Hoá Tại Các Mốc Cố Định

Mỗi repo Git có 1 thư mục .git/hooks/ chứa các script (thường là shell/Node) được Git tự động chạy tại đúng thời điểm nhất định — trước khi commit, sau khi nhận message commit, trước khi push... Quy ước rất đơn giản: script exit code 0 nghĩa là "cho qua", bất kỳ mã khác 0 nào nghĩa là "chặn lại, huỷ thao tác".

Hook Chạy khi nào Dùng để làm gì
pre-commit Ngay trước khi tạo commit Chạy lint/format, chặn commit nếu code chưa đạt chuẩn
commit-msg Sau khi message được viết, trước khi commit hoàn tất Kiểm tra định dạng message (VD: bắt buộc theo Conventional Commits)
pre-push Ngay trước khi push lên remote Chạy test suite, chặn push nếu có test fail
ℹ️ .git/hooks KHÔNG được version-control cùng repo
Thư mục .git/ hoàn toàn nằm ngoài phạm vi theo dõi của chính Git — clone 1 repo sẽ không mang theo hook nào cả. Đây là lý do các công cụ như Husky tồn tại: chúng lưu script hook dưới dạng file thường trong repo (được version-control bình thường), rồi tự cài đặt vào .git/hooks qua 1 bước postinstall, đảm bảo mọi thành viên team đều có cùng hook sau khi npm install.
🕳️ Cạm bẫy thường gặp: lạm dụng --no-verify
git commit --no-verify (hoặc git push --no-verify) bỏ qua hoàn toàn mọi hook — hữu ích trong tình huống khẩn cấp thực sự, nhưng nếu trở thành thói quen, nó vô hiệu hoá mọi lớp bảo vệ chất lượng mà team đã thiết lập. Coi đây là "van xả khẩn cấp", không phải lối tắt hàng ngày.

Sân chơi tương tác: Pre-commit/Pre-push Hook Simulator

Bật/tắt từng hook, đổi trạng thái "chất lượng" code hoặc test, rồi thử git commitgit push — quan sát hook chặn thao tác đúng lúc dựa theo exit code, và thử --no-verify để thấy nó bỏ qua hoàn toàn.

🪝 Sân chơi tương tác: Pre-commit/Pre-push Hook Simulator

Terminal giả lập

  • git commit -m "..."
  • git commit --no-verify -m "..."
  • git push
  • git push --no-verify

Nhật ký

git-hooks-live.js

2. Git Worktree: Nhiều Working Directory, 1 Repo

Bình thường, 1 working directory chỉ có thể checkout đúng 1 branch tại 1 thời điểm — muốn xem branch khác phải checkout/switch, kèm rủi ro phải stash thay đổi dở dang trước. git worktree add <path> <branch> tạo ra 1 thư mục làm việc hoàn toàn mới, checkout sẵn 1 branch khác, nhưng vẫn dùng chung đúng 1 object database (.git/) với working directory gốc — không cần clone lại, gần như tức thời.

🔬 Đào sâu: vì sao 1 branch không thể checkout ở 2 worktree cùng lúc?
Mọi worktree của cùng 1 repo chia sẻ chung object database và refs (.git/refs/heads/*). Nếu 2 worktree cùng checkout 1 branch, cả 2 sẽ cùng ghi vào đúng 1 con trỏ branch khi commit — dẫn tới xung đột cập nhật con trỏ không thể giải quyết nhất quán. Vì vậy Git chặn thẳng: mỗi branch chỉ được checkout tại đúng 1 worktree tại 1 thời điểm (trừ khi ở chế độ detached HEAD, xem lại Bài 3).
git checkout/switch thông thường git worktree add
Số branch xem cùng lúc Chỉ 1 (working directory duy nhất) Nhiều, mỗi worktree 1 branch riêng
Thay đổi dở dang khi chuyển branch Phải commit hoặc stash trước Không cần — mỗi worktree độc lập hoàn toàn
Chi phí thiết lập Tức thời (chỉ đổi con trỏ HEAD) Tức thời — dùng chung object database, không clone lại
Use case điển hình Chuyển việc tuần tự trên 1 nhánh tại 1 thời điểm Vừa code feature vừa build/test song song 1 hotfix khác
💡 Mẹo: git worktree list và dọn dẹp bằng remove
git worktree list liệt kê mọi worktree đang hoạt động cùng branch/commit của chúng. Khi xong việc, git worktree remove <path> gỡ bỏ sạch sẽ, giải phóng lại branch đó để có thể checkout ở nơi khác.

Sân chơi tương tác: Worktree Visualizer

Thử tạo thêm 1 worktree cho branch hotfix trong khi worktree gốc vẫn đang ở main, rồi thử tạo 1 worktree KHÁC cũng trỏ tới main — xem Git chặn lại vì sao.

🌲 Sân chơi tương tác: Worktree Visualizer

Terminal giả lập

  • git worktree add <path> <branch>
  • git worktree list
  • git worktree remove <path>

Nhật ký

git-worktree-live.js

Trắc nghiệm ôn tập

Câu 1: Nếu script pre-commit kết thúc với exit code khác 0, điều gì xảy ra?

Trắc nghiệm ôn tập

Câu 2: Vì sao clone 1 repo về máy khác sẽ KHÔNG mang theo các hook đã cấu hình?

Trắc nghiệm ôn tập

Câu 3: Vì sao 1 branch không thể được checkout ở 2 worktree khác nhau cùng lúc?

📖 Tài liệu tham khảo / References

Bài viết liên quan trong series

Bài 12: Tags & Aliases Nâng Cao Bài 10: Subtree & Submodule Quay lại Lộ trình Series Git