Git push bị reject? Cách xử lý an toàn trên Mac
🔧 Bài học từ thực tế: Lỗi "git push bị reject" thường xảy ra khi làm việc theo team — ai đó push commit, bạn không fetch kip, rồi bạn push code mà không biết có commit mới từ remote. Bài này hướng dẫn cách xử lý an toàn và cách tránh QA false positive ngoài ý muốn. Xem thêm hướng dẫn sync cơ bản push/pull/fetch hoặc cách xử lý conflict.
Mỗi lập trình viên làm việc với team từng gặp tình huống này: bạn code xong, chạy git push origin main, nhưng Git từ chối với dòng lỗi kiểu "rejected ... [non-fast-forward]". Điều gì xảy ra? Làm thế nào để sửa mà không mất code, mà không phải xoá branch và clone lại từ đầu? Bài viết này sẽ giải thích rõ ràng, cung cấp từng bước an toàn và cách tránh lỗi phổ biến mà nhiều người mắc phải.
Tại sao git push bị reject: Non-fast-forward là gì?
Git từ chối push khi phát hiện non-fast-forward — điều này có nghĩa là remote branch (trên server, vd GitHub) đã có commit mà local repository của bạn chưa có. Định nghĩa chính thức có thể tìm tại tài liệu Git chính thức.
Kịch bản thực tế:
- Lúc 9:00 sáng, bạn và đồng nghiệp A clone repo từ server. Cả hai ở commit
A123. - Lúc 10:00, A code xong 2 commit mới (
B456,C789) và push lên main. - Lúc 11:00, bạn code xong 1 commit của mình (
D012) và chạygit push origin main. - Git từ chối: vì server có
B456 → C789, nhưng bạn chỉ cóA123 → D012. Hai nhánh đã phân nhánh (diverge), Git không biết nên giữ lại cái nào.
Cách fix: bạn phải kéo những commit mới của A xuống, đặt commit của bạn lên trên, rồi mới được push.
Git fetch vs Git pull vs Git rebase: Hiểu đúng từng lệnh
Trước khi fix, bạn cần hiểu rõ ba lệnh thường nhầm lẫn:
Git fetch — "Lấy, nhưng chưa merge"
git fetch origin
Lệnh này download tất cả commit mới từ remote (GitHub/server) vào máy của bạn, nhưng không thay đổi file hiện tại. Điều này an toàn hoàn toàn — chỉ download, không merge hay xoá.
Sau git fetch, bạn có thể xem git log origin/main..HEAD để kiểm tra bạn có bao nhiêu commit ahead (phía trước) so với remote.
Git pull — "Fetch + merge (thường)"
git pull origin main
Mặc định, git pull = git fetch + git merge. Nghĩa là nó vừa download vừa merge, rồi tạo ra một commit merge nếu có xung đột (conflict). Commit merge này làm lịch sử Git trông "loạn".
Git rebase — "Sắp xếp lại commit: sạch nhưng cần cẩn"
git fetch origin
git rebase origin/main
Thay vì merge, rebase sắp xếp lại commit của bạn lên trên những commit mới từ remote. Kết quả là một đường thẳng sạch sẽ thay vì nhiều nhánh rối.
⚠️ Quy tắc vàng của rebase: Chỉ rebase commit mà bạn chưa push hoặc commit trên nhánh riêng của bạn. KHÔNG rebase commit công khai (người khác đã pull) vì sẽ khiến lịch sử bị thay đổi và gây khó chịu cho team.
Quy trình an toàn khi git push bị reject
Khi bạn gặp lỗi "rejected", hãy làm theo từng bước:
Bước 1: Fetch thay đổi mới nhất từ remote
git fetch origin
Không có hại, an toàn hoàn toàn. Lệnh này chỉ download, không merge hay xoá.
Bước 2: Kiểm tra tình trạng branch
git log origin/main..HEAD
Lệnh này hiển thị commit của bạn (HEAD) mà remote chưa có (origin/main). Nếu thấy commit của bạn ở đây, điều đó có nghĩa là bạn ahead.
Ngược lại, kiểm tra remote ahead:
git log HEAD..origin/main
Nếu thấy commit ở đây, điều đó có nghĩa là remote ahead — cần rebase.
Bước 3: Rebase an toàn (phương pháp được khuyến nghị)
git rebase origin/main
Lệnh này sắp xếp lại commit của bạn lên trên những commit mới từ remote. Nếu có xung đột (conflict), Git sẽ dừng và báo cho bạn giải quyết.
Nếu gặp conflict, hãy sửa file, rồi:
git add <file-name>
git rebase --continue
Nếu muốn hủy rebase (quay lại trạng thái trước):
git rebase --abortBước 4: Push lại
git push origin main
Lần này sẽ thành công vì bạn đã có tất cả commit từ remote.
Tại sao không dùng git push --force?
--force (hay -f) là lệnh rất nguy hiểm:
git push --force origin main # ⚠️ NGUY HIỂM! Đừng làm!
Lệnh này bỏ qua tất cả kiểm tra, ghi đè bất kỳ thứ gì trên server. Nếu đồng nghiệp vừa push commit lên server, --force của bạn sẽ xoá commit đó đi. Họ sẽ rất tức giận.
Khi nào thì dùng --force?
- Rất hiếm, và phải báo trước team.
- Ví dụ: bạn làm việc trên nhánh riêng
feature/bao-mat-password, commit được push lên, nhưng bạn phát hiện lỗi bảo mật, dùnggit commit --amendđể sửa, rồigit push --forceđể cập nhật nhánh đó (chỉ nếu không ai khác đang pull nhánh này). - KHÔNG bao giờ
git push --forcevàomainhoặc nhánh dùng chung.
Thay --force, dùng git push --force-with-lease nếu thật sự cần — nó an toàn hơn một chút vì sẽ từ chối nếu có commit mới từ người khác.
QA false positive do .venv trong repo: Bài học thực tế
Có một vấn đề phổ biến khác khiến developer mắc lỗi: commit thư mục .venv (hoặc node_modules, vendor/) vào repo.
Kịch bản:
- Bạn tạo virtualenv:
python3 -m venv .venvđể cài dependencies. - Vô tình commit
.venv/vào repo (quên thêm vào.gitignore). - Đồng nghiệp B clone repo, anh ta có
.venvlạ hoặc khác phiên bản dependencies. - Chạy
python3 qa_check.py, test fails trên máy B nhưng pass trên máy bạn. - Cả hai bối rối: "Why fail here but pass on yours?" — False positive do environment mismatch.
Cách fix:
- Thêm vào
.gitignore:
.venv/
venv/
node_modules/
- Tạo virtualenv ở ngoài repo hoặc tại
/tmp:
python3 -m venv /tmp/project-qa-venv
source /tmp/project-qa-venv/bin/activate
pip install -r requirements.txt
python3 qa_check.py
- Hoặc tạo script tự động:
#!/bin/bash
QA_VENV="/tmp/project-qa-venv"
python3 -m venv "$QA_VENV"
source "$QA_VENV/bin/activate"
pip install -r requirements.txt
python3 qa_check.py
Lợi ích:
- Không phải commit virtual env.
- Mỗi máy tự cài dependencies sạch sẽ.
- QA tests chạy đúng, không false positive.
Pre-push checklist cho macOS
Trước mỗi git push, hãy chạy checklist này để tránh lỗi:
-
Fetch mới nhất:
git fetch origin -
Kiểm tra branch nào được push:
git branch -vvNên thấy
[origin/main]hoặc nhánh tracking của bạn. -
Xem lại log commit của bạn:
git log origin/main..HEAD --oneline -
Rebase nếu cần:
git rebase origin/main -
Chạy local QA (nếu có):
python3 qa_check.py(Chắc chắn
.venvkhông trong repo, hoặc dùng/tmp/project-qa-venv). -
Push:
git push origin main
Sử dụng GitHub CLI (gh) để kiểm tra trước push
Nếu bạn dùng GitHub CLI (gh), có thể kiểm tra trạng thái PR/branch:
gh pr list --draft=false --state=open
Hoặc kiểm tra workflows:
gh run list
Điều này giúp bạn biết có QA failure hay CI đỏ trước khi push thêm.
Tóm lại: Cách an toàn và quy tắc vàng
Git push bị reject không phải lỗi nghiêm trọng — chỉ là Git bảo vệ bạn khỏi việc mất commit. Quy trình an toàn:
git fetch origin— lấy thay đổi mới nhất (an toàn).git log HEAD..origin/main— kiểm tra xem remote có commit nào mới.git rebase origin/main— sắp xếp lại commit của bạn (sạch hơn merge).git push origin main— push lên.
Tránh:
git push --forcevàomainhoặc nhánh dùng chung.- Commit
.venv/,node_modules/, hoặc file tạm vào repo. - Để
.venvtrong repo mà không sửa.gitignore(gây QA false positive).
Khi team làm việc cùng nhau, những qui tắc đơn giản này giúp mọi người không bị mất code, lịch sử Git sạch sẽ, và QA tests chạy đúng trên tất cả máy.
Hẹn gặp lại ở bài tiếp theo về cách quản lý nhánh (branch) hiệu quả! 🚀
Tham khảo & Nguồn dữ liệu
1. Liên kết bên ngoài được sử dụng trong bài viết
2. Liên kết nội bộ liên quan
3. Bản quyền & Ghi nguồn
Một phần dữ liệu trong bài viết được tham khảo từ tài liệu Git chính thức. Mọi thương hiệu, tên sản phẩm và tài liệu gốc thuộc quyền sở hữu của chủ sở hữu tương ứng. Bài viết chỉ trích dẫn, tổng hợp và phân tích — không nhằm thay thế tài liệu chính thức.
Câu hỏi thường gặp
Non-fast-forward là gì và tại sao nó khiến git push bị reject?
Git pull rebase khác gì so với git merge, và tại sao nó an toàn?
Tại sao git push --force nguy hiểm và khi nào mới dùng?
QA false positive do .venv là gì? Làm sao để tránh?
Làm sao để chắc chắn push của tôi không bị reject lần tới?
💬 BÌNH LUẬN
Đăng nhập GitHub để comment. Hỗ trợ markdown, reaction, reply.