Giới thiệu
Nếu bạn đã từng làm việc trong một monorepo với nhiều đội ngũ đẩy mã hàng ngày, bạn sẽ hiểu nỗi đau khi nhánh tính năng của bạn đã sẵn sàng, tất cả các kiểm tra đã thông qua và ngay khi bạn chuẩn bị hợp nhất, GitHub chặn lại vì nhánh của bạn đã lỗi thời so với nhánh main. Bây giờ, bạn phải kéo, tái cấu trúc hoặc hợp nhất, chờ đợi các bản xây dựng chạy lại và mất thêm 20 phút nữa.
Chu trình này thật sự rất khó chịu và tốn kém cho chúng tôi. Chúng tôi cần giữ các nhánh đồng bộ với main mà không làm chậm lại quy trình làm việc của kỹ sư. Đó là khi chúng tôi chuyển sang các Git hooks và cụ thể là pre-push hook.
Tình huống Vấn đề
Trong thiết lập monorepo của chúng tôi, mỗi kỹ sư đều đẩy mã vào cùng một kho chứa. Với việc nhánh main thường xuyên được cập nhật, các nhánh tính năng thường bị lệch khỏi đồng bộ. Việc hợp nhất các nhánh đó mà không kéo nhánh main trước sẽ có nguy cơ ghi đè lên những thay đổi quan trọng.
Nỗ lực Đầu tiên: Quy tắc bảo vệ nhánh
Chúng tôi bắt đầu với các quy tắc bảo vệ nhánh của GitHub, yêu cầu các nhánh phải được cập nhật với main trước khi hợp nhất.
Mặc dù hiệu quả trong việc phát hiện các nhánh lỗi thời, điều này đã tạo ra những điểm đau mới.
- Các bản xây dựng Jenkins của chúng tôi mất hơn 8 phút và phải được chạy lại mỗi khi có một cam kết mới được thêm vào nhánh.
- Các kỹ sư phải nhanh chóng hợp nhất sau khi nhận được phê duyệt hoặc có nguy cơ bị tụt lại phía sau lần nữa.
Cuối cùng, chúng tôi đã phải loại bỏ quy tắc này, nó đã đảm bảo tính chính xác nhưng với cái giá là năng suất của kỹ sư.
Thay đổi Cuộc chơi: Pre-Push Hook
Sau nhiều cuộc thảo luận và nghiên cứu, chúng tôi đã xem xét các Git hooks. Vì chúng tôi đã sử dụng Husky cho pre-commit hook, việc mở rộng nó cho pre-push cảm thấy rất tự nhiên.
Dưới đây là cách mà pre-push hook của chúng tôi hoạt động:
- Một kỹ sư tạo một nhánh từ
main, làm việc trên nhánh này và chuẩn bị để đẩy. - Khi chạy
git push, pre-push hook tự động chạy. - Hook thực hiện một vài kiểm tra:
- Đảm bảo rằng nhánh không phải là
main(chúng tôi cũng có các kiểm tra riêng biệt ngăn chặn việc đẩy trực tiếp vàomain). - Xác nhận rằng nhánh có một upstream.
- Kiểm tra xem nhánh có đang bị lệch so với
mainhay không.
- Đảm bảo rằng nhánh không phải là
- Nếu nhánh đang lùi lại so với nhánh
main:- Nó kéo nhánh
mainmới nhất từ xa và hợp nhất vào nhánh tính năng. - Nếu có xung đột, hook sẽ dừng lại và hiển thị thông báo lỗi yêu cầu kỹ sư giải quyết chúng thủ công trước khi đẩy lại.
- Nếu không tìm thấy xung đột, việc hợp nhất sẽ được cam kết và quá trình đẩy sẽ tiếp tục.
- Nó kéo nhánh
Kết quả: Mọi nhánh đều được đảm bảo là đồng bộ với main tại thời điểm đẩy.
Những điều cần lưu ý
Mặc dù giải pháp này đã mang lại sự cải thiện lớn, nhưng nó không phải là không có vấn đề. Một số điều cần lưu ý.
- Bỏ qua hooks: Các kỹ sư vẫn có thể sử dụng
git push --no-verifyđể bỏ qua việc chạy hook. - Hợp nhất muộn: Ngay cả sau khi được phê duyệt, nếu việc hợp nhất diễn ra muộn, nhánh vẫn có thể bị lệch.
- Các vấn đề với IDE: Chúng tôi đôi khi thấy IDE hiển thị "các thay đổi chưa được đẩy" mặc dù mã đã được đẩy lên nhánh từ xa. Chạy
git fetchthường sẽ giải quyết điều này.
Kết luận
Việc thêm một pre-push hook vào quy trình làm việc của chúng tôi đã là một thay đổi đơn giản nhưng mạnh mẽ. Nó tự động hóa một trong những điểm đau khó chịu nhất trong một monorepo phát triển nhanh - Giữ các nhánh tính năng đồng bộ với main
Cải tiến nhỏ này đã tiết kiệm hàng giờ thời gian xây dựng lãng phí, giảm xung đột khi hợp nhất và cho phép kỹ sư tập trung vào việc viết mã thay vì vật lộn với Git.
Nếu đội ngũ của bạn đang gặp phải vấn đề tương tự, hãy thử nghiệm với pre-push hooks.