Shift Left: Tại sao phải chờ đợi Cloud?
Hầu hết các lập trình viên coi CI/CD là một quy trình xa vời chạy trên server từ xa như GitHub Actions hoặc Jenkins. Bạn push code, đi pha cà phê, và đợi năm phút để thấy dấu tích xanh. Nếu thay vào đó bạn thấy một dấu ‘X’ đỏ, bạn phải chuyển đổi ngữ cảnh (context-switch), sửa một lỗi đánh máy ngớ ngẩn và bắt đầu lại chu kỳ đó. Vòng lặp phản hồi này là một kẻ sát nhân thầm lặng đối với năng suất làm việc.
Git Hooks đảo ngược kịch bản này bằng cách đưa các bước kiểm tra thiết yếu đó về máy cục bộ của bạn. Đây là những script đơn giản mà Git sẽ tự động kích hoạt trước hoặc sau các sự kiện như commit hoặc push. Bằng cách phát hiện một dấu chấm phẩy bị thiếu hoặc một unit test bị lỗi ngay trên laptop, bạn sẽ giúp nhóm của mình tránh được các bản build bị hỏng. Tôi đã thấy nhiều đội ngũ giảm tỷ lệ thất bại CI hơn 40% chỉ bằng cách triển khai một quy trình pre-commit cơ bản.
Hãy coi nó như một trợ lý cá nhân giúp soát lỗi công việc trước khi bạn nộp bài. Nó ngăn chặn những khoảnh khắc đáng xấu hổ khi một lỗi cú pháp nhỏ làm dừng toàn bộ pipeline của mọi người khác.
Những Hook này nằm ở đâu?
Mỗi repository Git đều có một công cụ tự động hóa tích hợp sẵn được ẩn giấu ngay trước mắt. Khi bạn chạy lệnh git init, Git sẽ tạo ra một thư mục .git/hooks. Bên trong đó, bạn sẽ tìm thấy một vài file mẫu.
cd .git/hooks
ls -l
Bạn sẽ thấy các file như pre-commit.sample và pre-push.sample. Đây chỉ là các shell script. Để kích hoạt một hook, hãy xóa phần mở rộng .sample và đảm bảo file đó có quyền thực thi. Mọi chuyện đơn giản như vậy thôi.
Có hai loại hook cần lưu ý:
- Client-side hooks: Những hook này chạy trên máy tính của bạn. Chúng hoàn hảo cho việc linting, formatting và các unit test nhanh.
- Server-side hooks: Những hook này chạy trên server từ xa. Chúng được sử dụng để thực thi các quy ước đặt tên branch hoặc kích hoạt thông báo triển khai.
Đối với hầu hết công việc hàng ngày, các client-side hook như pre-commit mang lại hiệu quả nhanh chóng nhất.
Tạo “Người gác cổng” đầu tiên (Pre-Commit)
Hãy cùng xây dựng một hook để chặn commit nếu code chưa chỉn chu. Điều này giúp giữ cho repository sạch sẽ và đảm bảo mọi người đều tuân theo cùng một style guide. Chúng ta sẽ sử dụng ví dụ với Node.js, nhưng bạn có thể thay thế bằng flake8 của Python hoặc gofmt của Go.
Đầu tiên, hãy tạo file và cấp quyền phù hợp:
touch .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Thêm logic này vào file. Nó sẽ ra lệnh cho Git: “Chạy linter. Nếu phát hiện vấn đề, hãy dừng commit ngay lập tức.”
#!/bin/sh
echo "🔍 Đang kiểm tra style code..."
npm run lint
# Lấy kết quả của lệnh vừa chạy
status=$?
if [ $status -ne 0 ]; then
echo "❌ Linting thất bại! Hãy sửa các lỗi trên trước khi commit."
exit 1
fi
echo "✅ Style ổn rồi. Đang tiến hành commit."
exit 0
Giờ đây, mỗi khi bạn gõ git commit, script này sẽ chạy. Nếu code của bạn chưa chuẩn, Git sẽ hủy thao tác. Bạn buộc phải sửa lỗi ngay tại máy cục bộ trong vài giây thay vì đợi hàng phút để server CI thông báo cho bạn cùng một điều đó.
Vấn đề “Chạy tốt trên máy tôi”
Thư mục .git/hooks tiêu chuẩn có một nhược điểm lớn: Git không theo dõi nó. Nếu bạn tạo ra một hook tuyệt vời, đồng đội của bạn sẽ không thấy nó khi họ clone dự án. Để khắc phục điều này, hãy sử dụng một công cụ như Husky (cho JavaScript) hoặc pre-commit framework (cho Python và các dự án đa ngôn ngữ).
Với Husky, bạn có thể lưu trữ các hook trong thư mục .husky và thư mục này sẽ được quản lý bởi version control. Việc thiết lập rất nhanh chóng:
npx husky-init && npm install
npx husky add .husky/pre-commit "npm test"
Điều này đảm bảo mọi lập trình viên trong nhóm đều chạy các bước kiểm tra giống nhau. Không có ngoại lệ.
Pre-Push: Tấm lưới an toàn cuối cùng
Mặc dù linting diễn ra nhanh chóng, nhưng có lẽ bạn không muốn chạy toàn bộ bộ test tích hợp (integration test) mất 10 phút mỗi khi lưu một thay đổi nhỏ. Đây là lúc hook pre-push tỏa sáng. Nó chỉ chạy khi bạn cố gắng gửi code lên server từ xa.
#!/bin/sh
echo "🧪 Đang chạy toàn bộ test suite trước khi push..."
npm test
if [ $? -ne 0 ]; then
echo "❌ Tests thất bại. Đã hủy lệnh push để bảo vệ main branch."
exit 1
fi
exit 0
Bằng cách phân chia quy trình tự động hóa—linting khi commit và testing khi push—bạn giữ cho quy trình làm việc cục bộ luôn nhanh chóng trong khi vẫn bảo vệ được codebase chung.
Xử lý sự cố và Bỏ qua Hook
Nếu một hook không hoạt động, hãy kiểm tra các bước cơ bản. Nó có quyền thực thi không? Hãy chạy chmod +x .git/hooks/pre-commit. Tên file có chính xác không? Git sẽ không nhận diện pre-commit.sh. Ngoài ra, hãy nhớ rằng các hook chạy trong một shell không tương tác (non-interactive shell). Luôn sử dụng các đường dẫn cục bộ như ./node_modules/.bin/eslint để tránh lỗi “command not found”.
Đôi khi bạn có thể cần bỏ qua các quy tắc, ví dụ như khi cần hotfix khẩn cấp. Bạn có thể bỏ qua các hook bằng cách thêm một flag duy nhất:
git commit -m "Emergency fix" --no-verify
Hãy hạn chế sử dụng cách này. Nếu bạn thấy mình dùng --no-verify hàng ngày, có khả năng các bài test của bạn quá chậm hoặc các quy tắc quá khắt khe. Một hook tốt nên là một sự trợ giúp, chứ không phải một rào cản.
Lời kết
Tự động hóa không chỉ dành cho các server cloud lớn. Nó bắt đầu ngay tại bàn phím của bạn. Bằng cách dành ra mười phút để thiết lập Git Hooks, bạn có thể tiết kiệm hàng giờ chờ đợi cộng dồn mỗi tháng. Hãy bắt đầu từ việc nhỏ với một linter, sau đó mở rộng sang quét mã bí mật (secret-scanning – để ngăn rò rỉ API key) hoặc tự động format code. Server CI của bạn — và cả đồng đội của bạn nữa — sẽ cảm ơn bạn vì điều đó.

