Giới thiệu vấn đề: Cơn ác mộng mang tên git push –force
Hơn hai năm trước, team mình chạy nước rút cho đợt release cổng thanh toán. Sau khi rebase nhánh tính năng để dọn dẹp commit, mình tiện tay gõ: git push origin feature/checkout --force. Mọi thứ tưởng như êm đẹp. Đúng 10 phút sau, cậu bạn phụ trách tích hợp VNPay hớt hải chạy sang bàn mình. Mặt cậu ấy tái mét: 4 commit fix bug vừa đẩy lên nhánh chung đã bốc hơi sạch sẽ.
Cảm giác lúc đó thực sự thảm họa. Cờ -f (hoặc --force) hoạt động hoàn toàn mù quáng. Nó ép server nhận nhánh local của bạn, bất chấp ai đó vừa đẩy thêm code mới lên remote. Sau sự cố nhớ đời khiến cả team phải thức đến 2 giờ sáng cứu code, bọn mình đổi luật: cấm tuyệt đối git push --force và chuyển hẳn sang --force-with-lease. Sau 6 tháng áp dụng, lệnh này đã cứu team mình không dưới 10 bàn thua trông thấy.
Khái niệm cốt lõi: Cơ chế hoạt động của –force-with-lease
Về cơ bản, --force-with-lease vẫn cho phép viết lại lịch sử commit. Điểm khác biệt nằm ở chỗ: nó kiểm tra trước khi đè.
Cơ chế này tương tự Optimistic Locking trong database. Git so sánh ref hiện tại của nhánh trên remote với remote tracking branch (như origin/feature-branch) đang lưu ở máy bạn:
- Trường hợp an toàn: Commit SHA trên remote server trùng khớp với remote tracking branch local. Nghĩa là chưa ai đẩy thêm commit mới kể từ lần bạn
git fetchgần nhất. Git lập tức cho phép ghi đè. - Trường hợp có xung đột: Đồng nghiệp đã kịp đẩy code mới lên remote trong lúc bạn rebase. SHA trên server đã khác. Git lập tức chặn đứng thao tác push và ném ra cảnh báo lỗi.
So sánh thực tế: –force đối đầu –force-with-lease
Bảng đối chiếu dưới đây sẽ giúp bạn hình dung rõ sự khác biệt giữa hai cờ:
| Tiêu chí | git push --force |
git push --force-with-lease |
|---|---|---|
| Hành vi ghi đè | Ghi đè tuyệt đối, phớt lờ trạng thái remote | Chỉ ghi đè nếu remote chưa có commit mới lạ |
| Bảo vệ code đồng đội | Không (dễ xóa sạch commit của người khác) | Có (chặn push ngay khi phát hiện thay đổi mới) |
| Rủi ro tai nạn | Rất cao khi nhiều người làm chung một branch | Cực thấp, kiểm soát chặt chẽ rủi ro |
Thực hành chi tiết: Các bước áp dụng trên dự án thực tế
1. Cú pháp cơ bản thường dùng
Mỗi lần squash commit, rebase nhánh hoặc chạy git commit --amend ở máy cá nhân, bạn hãy thay thế cờ -f bằng lệnh sau:
# Đẩy code an toàn lên nhánh đang làm việc
git push --force-with-lease origin feature/payment-gateway
2. Mô phỏng tình huống bị chặn khi có người đẩy code mới
Giả sử bạn và bạn An cùng làm việc trên nhánh feature/login. Bạn vừa rebase local để gộp 3 commit thành 1. Cùng lúc đó, An vừa đẩy một commit sửa CSS lên GitHub:
# Bạn thực hiện force push an toàn
$ git push --force-with-lease origin feature/login
# Kết quả Git trả về:
To github.com:org/repo.git
! [rejected] feature/login -> feature/login (stale info)
error: failed to push some refs to 'github.com:org/repo.git'
Dòng thông báo stale info xuất hiện chính là lúc chốt an toàn hoạt động. Git thấy commit remote đã đi trước remote tracking branch ở máy bạn, nên từ chối đè.
3. Quy trình 4 bước xử lý lỗi stale info
Đừng hoảng khi gặp lỗi này. Hãy xử lý tuần tự theo 4 bước sau:
# Bước 1: Kéo thông tin mới nhất từ remote về local
git fetch origin
# Bước 2: Kiểm tra nhanh xem đồng đội vừa push thêm những gì
git log --oneline feature/login..origin/feature/login
# Bước 3: Rebase nhánh local của bạn lên trên commit mới từ remote
git rebase origin/feature/login
# Bước 4: Thử push lại an toàn
git push --force-with-lease origin feature/login
Toàn bộ thay đổi của cả hai bên đều được gom lại nguyên vẹn. Không một dòng code nào bị mất oan.
4. Điểm mù cần lưu ý: coi chừng auto-fetch chạy ngầm
Dù an toàn hơn nhiều, --force-with-lease vẫn có một kẽ hở kỹ thuật. Lệnh này chỉ so sánh dựa vào remote tracking branch ở máy bạn. Nếu các IDE như VS Code hay JetBrains bật tính năng auto-fetch định kỳ, Git local sẽ tự động kéo ref mới về ngầm. Lúc này, --force-with-lease lầm tưởng bạn đã biết về commit mới của đồng nghiệp. Lệnh push vẫn ghi đè như thường!
Gặp những nhánh cực kỳ nhạy cảm, bạn hãy chỉ định đích danh SHA ref của remote trực tiếp trong tham số:
# Chỉ cho phép ghi đè nếu commit trên remote đúng bằng SHA a1b2c3d
git push --force-with-lease=feature/login:a1b2c3d origin feature/login
5. Thiết lập Git Alias để gõ nhanh hơn
Gõ cả cụm --force-with-lease khá dài dòng và dễ nản. Để giữ thói quen tốt mà không tốn công gõ phím, bạn hãy thêm alias vào file ~/.gitconfig:
# Đặt alias pf cho nhanh gọn
git config --global alias.pf "push --force-with-lease"
Từ giờ, mỗi khi cần force push, bạn chỉ cần gõ đúng 4 từ:
git pf origin feature/my-branch
Kết luận: Thói quen nhỏ, khác biệt lớn
Thay đổi từ -f sang --force-with-lease chỉ mất vài giây cài đặt. Đổi lại, bạn có sự an tâm tuyệt đối mỗi khi rebase hay sửa commit history. Đừng để một cú gõ phím vội vàng biến công sức cả ngày của đồng đội thành mây khói. Hãy tạo alias ngay hôm nay và chia sẻ kinh nghiệm này cho cả team của bạn.
