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.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.
--no-verifygit 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 commit và
git 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.
Terminal giả lập
git commit -m "..."git commit --no-verify -m "..."git pushgit push --no-verify
Nhật ký
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.
.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 |
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.
Terminal giả lập
git worktree add <path> <branch>git worktree listgit worktree remove <path>
Nhật ký
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?