Chuyển đến nội dung chính

Git Push Force: Cách hoạt động và cách dùng an toàn

Tìm hiểu cách git push force ghi đè lịch sử nhánh, cách dùng an toàn và cách khôi phục commit mà không phá vỡ quy trình làm việc của nhóm.
· 7 phút đọc

Khám phá cùng AI

Có lẽ bạn đã từng gặp tình huống này với vai trò nhà phát triển: Bạn vừa nhận ra mã của mình có vấn đề trong commit cuối. Để hoàn tác sai sót, bạn chạy vài lệnh và viết lại lịch sử cục bộ. Khi bạn chạy git push --force để dọn dẹp mọi thứ, đồng đội thông báo rằng một số commit bị thiếu hoặc pipeline của bạn có bản dựng lỗi.

Trong bài viết này, tôi sẽ giải thích git push --force thực sự làm gì, khi nào nên dùng và cách tránh lỗi. Nếu bạn mới bắt đầu với Git, tôi khuyến nghị tham gia khóa học our Introduction to Git để tìm hiểu về kiểm soát phiên bản. Ngoài ra, tôi thấy Git Cheat Sheet mà bạn có thể tải xuống là tài liệu tham khảo hữu ích vì có đầy đủ thuật ngữ và lệnh Git phổ biến nhất.

Khi Bạn Nghĩ Rằng Mình Cần git push --force

Giả sử bạn đang dọn dẹp lịch sử commit cục bộ trước khi đẩy công việc của mình. Để gọn gàng trước khi hợp nhất, bạn chạy git rebase -i main. Mọi thứ trông hoàn hảo ở máy bạn, nên bạn thử cập nhật nhánh từ xa bằng một lệnh git push đơn giản. Nhưng thay vì thông báo thành công như thường lệ, Git lại báo lỗi.

Bạn có thể gặp tình huống khác khi vô tình commit dữ liệu nhạy cảm, chẳng hạn một API key hoặc mật khẩu, rồi đẩy lên remote. Sau khi viết lại lịch sử cục bộ để loại bỏ commit gây lỗi, bạn thấy một lần đẩy bình thường không cập nhật kho từ xa và dữ liệu nhạy cảm vẫn còn đó. Bạn lại nhận thông báo lỗi.

! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'origin'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.,
hint: 'git pull ...') before pushing again.

Lỗi “non-fast-forward” này là lưới an toàn của Git, cảnh báo rằng lịch sử của bạn không khớp với máy chủ. Lúc này, rất dễ bị cám dỗ chạy git push --force để vượt qua lỗi.

Điều đó có thể ổn nếu bạn là người duy nhất làm việc trên nhánh. Tuy nhiên, với dự án dùng chung, nó rất dễ gây nhầm lẫn hoặc xóa mất công việc của người khác.

git push --force Thực Sự Làm Gì

Thông thường, Git chỉ cho phép bạn đẩy thay đổi nếu nhánh cục bộ của bạn chứa mọi thứ đã có trên remote, cộng với commit mới của bạn. Tuy nhiên, đôi khi bạn có thể viết lại lịch sử commit thông qua git rebase, squash, hoặc loại bỏ dữ liệu nhạy cảm. Khi làm vậy, nhánh cục bộ của bạn sẽ khác với nhánh từ xa. Rồi khi bạn cố đẩy commit mới, Git sẽ báo lỗi để bảo vệ nhánh từ xa khỏi mất mát công việc.

Dùng git push --force yêu cầu Git bỏ qua kiểm tra an toàn và ghi đè nhánh từ xa bằng nội dung nhánh cục bộ của bạn. 

Trông sẽ như thế này:

git push --force origin main

Lệnh này sẽ cập nhật nhánh main trên remote để khớp với main cục bộ của bạn và xóa mọi commit không có trong nhánh cục bộ. 

Hãy hình dung nhánh Git như một chương trong cuốn sách chung mà cả nhóm đang cùng viết. Một lần đẩy tiêu chuẩn giống như thêm đoạn văn mới vào cuối chương. Còn git push --force mạnh hơn và xé cả chương hiện tại ra, thay hoàn toàn bằng phiên bản của bạn. 

Rủi ro khi dùng git push --force là cộng tác viên có thể mất công việc nếu họ dựa thay đổi trên các commit mà bạn vừa xóa sạch. Ở phần tiếp theo, chúng ta sẽ xem các biện pháp cần lưu ý khi làm việc với lệnh --force.

Vì Sao Điều Này Có Thể Phá Vỡ Mọi Thứ Với Nhóm Của Bạn

Nếu bạn cưỡng bức đẩy thay đổi lên nhánh dùng chung như main hoặc develop, bạn có thể gặp các vấn đề sau:

  • Nhánh cục bộ của người khác bị lệch nhịp: Nếu đồng đội đã kéo các commit cũ mà bạn vừa xóa khỏi remote, lịch sử cục bộ của họ sẽ không còn khớp với máy chủ. Nhánh của họ sẽ tham chiếu các commit đã “biến mất”, gây nhầm lẫn và 
  • Khi pull sẽ sinh merge rối rắm hoặc lỗi: Khi ai đó cố git pull sau khi bạn force-push, Git sẽ không biết hòa giải lịch sử đã viết lại với chuỗi commit cục bộ của họ ra sao. Điều này thường dẫn tới các merge lạ, lỗi khó hiểu, hoặc yêu cầu họ tự can thiệp bằng git fetch, git reset, thậm chí clone lại nhánh.
  • Pipeline CI/CD có thể lỗi: Pipeline thường phụ thuộc vào hash commit nhất quán và lịch sử tuyến tính. Force push có thể khiến chúng fail kiểm thử, triển khai sai mã, hoặc sập khi build lại trên commit lỗi thời.

Hãy xem khóa học CI/CD for Machine Learning của chúng tôi để hiểu cách xây dựng quy trình CI/CD. Tôi cũng khuyến nghị khóa học Introduction to Data Versioning with DVC để học sự khác nhau giữa quản lý phiên bản dữ liệu và mã nguồn.

Minh họa thế này: Bạn đang ở nhánh feature cùng một đồng đội. Bạn dọn dẹp lịch sử cục bộ, rồi chạy git push --force. Vài phút sau, đồng đội của bạn đẩy thay đổi của họ. Họ thấy Git báo lỗi. Khi họ pull, họ gặp xung đột merge và lịch sử commit bị rối. Trong khi đó, pipeline CI của bạn fail vì thiếu commit. Giờ thì đồng đội mất thời gian gỡ rối nhánh, còn triển khai bị trì hoãn.

Chỉ một lần force push đã kích hoạt tất cả điều đó.

Lựa Chọn An Toàn Hơn: git push --force-with-lease

Để tránh các vấn đề như vậy, tôi khuyến nghị dùng git push --force-with-lease. Lệnh này thêm một bước kiểm tra an toàn khi đẩy lên nhánh từ xa để tránh các commit bất ngờ.

git push --force-with-lease origin main

Hãy coi --force-with-lease như “hỏi xem có thông thoáng không trước khi nhảy vào”. Trước khi làm gì, nó đảm bảo không ai khác đã thay đổi nhánh. Nếu mọi thứ vẫn như lần bạn thấy gần nhất, lịch sử của bạn sẽ được cập nhật. Nhưng nếu có thay đổi mới mà bạn chưa biết, Git sẽ dừng lại và nhắc bạn xem xét trước. Vì vậy, lệnh này luôn bảo vệ cộng tác viên khỏi bị ghi đè ngoài ý muốn.

Cách Khôi Phục Sau Một Lần Force Push Sai

Nếu bạn mất một số commit, đừng lo vì vẫn có thể khôi phục. Git luôn lưu lại lịch sử thay đổi của commit hiện tại, kể cả khi viết lại, và lưu trong reflog.

Cách khôi phục commit bị mất như sau:

Bước 1: Dùng git reflog để tìm commit bị mất

Chạy git reflog để xem lịch sử nhánh của bạn.

git reflog

Bạn có thể thấy commit của mình như sau:

abc1234 HEAD@{1}: push: force push
def5678 HEAD@{2}: commit: add new feature

Bước 2: Khôi phục commit đã mất

Khi đã xác định được hash commit cần khôi phục, dùng lệnh dưới đây để chuyển tới commit cụ thể.

git checkout def5678

Bước 3: Tạo nhánh mới

Để khôi phục tệp một cách an toàn, hãy tạo nhánh git mới.

git checkout -b recovery-branch

Bước 4: Khôi phục nhánh từ xa

Giờ hãy đẩy các commit đã khôi phục lên nhánh:

git push origin recovery-branch

Lưu ý rằng dữ liệu reflog chỉ tồn tại trên máy cục bộ. Do đó, bạn có thể không khôi phục được commit đã mất nếu không ai trong nhóm từng lưu chúng trong môi trường cục bộ.

Tôi khuyến nghị bạn tham gia khóa học Intermediate Git để tìm hiểu thêm về cộng tác và làm việc với nhánh trong Git.

Thực Hành Tốt Để Dùng git push --force An Toàn

Để giảm khả năng gây lỗi, hãy hình thành các thói quen sau:

  • Ưu tiên --force-with-lease thay vì --force:  Cách này an toàn hơn vì kiểm tra xem nhánh từ xa có thay đổi kể từ lần fetch gần nhất của bạn hay không. Tôi sẽ giúp bảo vệ đồng đội khỏi bị ghi đè ngoài ý muốn.

  • Tránh force-push lên nhánh dùng chung: Không bao giờ force-push lên các nhánh dùng chung như main, master, develop hoặc release. Chỉ force push lên nhánh tính năng của bạn, nơi bạn là người đóng góp duy nhất, để tránh gián đoạn.

  • Thông báo cho nhóm trước khi force-push: Nếu buộc phải force-push lên nhánh dùng chung, hãy báo trước cho nhóm. Điều này cho phép họ lưu công việc và tránh mất mát.

  • Dùng nhánh được bảo vệ: Bạn cũng có thể bật bảo vệ cho nhánh khi dùng các nền tảng như GitHub, GitLab và Bitbucket. Điều này hạn chế chỉnh sửa trực tiếp và ngăn force push nhầm lên các nhánh quan trọng.

Nếu bạn muốn tìm hiểu thêm về quản lý repo riêng tư, hãy xem khóa học Introduction to GitHub Concepts của chúng tôi để hiểu cách review pull request khi cộng tác trên GitHub.

Kết luận

git push --force cung cấp một cách hữu ích để viết lại lịch sử repo, dù là để dọn commit hay loại bỏ dữ liệu nhạy cảm. Luôn thận trọng khi dùng lệnh này để tránh phá vỡ quy trình làm việc của nhóm.

Bất cứ khi nào có thể, hãy dùng --force-with-lease thay thế. Nó cho bạn nhiều kiểm soát hơn mà không liều làm ảnh hưởng tới công việc của người khác. Chỉ cần cẩn trọng và giao tiếp tốt, bạn có thể giữ lịch sử Git sạch sẽ mà không gây rắc rối cho nhóm.

Tôi khuyến nghị bạn xem các lộ trình kỹ năng Git Fundamentals và GitHub Foundations để trở thành chuyên gia về Git.

Allan Ouko

Tác giả

Allan Ouko

Biên tập viên kỹ thuật về Khoa học dữ liệu với kinh nghiệm thực tế trong phân tích dữ liệu, trí tuệ doanh nghiệp và khoa học dữ liệu. Tôi viết nội dung thực tiễn, tập trung vào ngành về SQL, Python, Power BI, Databricks và kỹ thuật dữ liệu, dựa trên công việc phân tích trong thế giới thực. Bài viết của tôi kết nối chiều sâu kỹ thuật với tác động kinh doanh, giúp các chuyên gia chuyển đổi dữ liệu thành những quyết định vững chắc.

FAQs

Những rủi ro khi dùng git push --force là gì?

Nó có thể ghi đè các commit trên nhánh từ xa, khiến đồng đội mất công việc hoặc gặp xung đột merge khó hiểu.

Làm thế nào để dùng git push --force-with-lease một cách an toàn?

Hãy dùng git push --force-with-lease  thay vì --force để đảm bảo nhánh từ xa không thay đổi kể từ lần fetch gần nhất của bạn, giúp ngăn ghi đè ngoài ý muốn.

Những trường hợp nào cần dùng git push --force?

git push --force  có thể cần thiết khi bạn đã rebase commit cục bộ, loại bỏ dữ liệu nhạy cảm khỏi lịch sử, hoặc dọn dẹp lịch sử commit trước khi hợp nhất nhánh tính năng.

Làm thế nào để hoàn tác một git push --force mà tôi hối tiếc?

Để hoàn tác git push --force hãy chạy git reflog để tìm commit trước đó, rồi khôi phục bằng cách checkout commit đó và force-push nhánh đã sửa.

Các thực hành tốt nhất để tránh sai sót với git push --force là gì?

Dùng --force-with-lease, tránh force-push lên nhánh dùng chung, giao tiếp với nhóm, và bảo vệ các nhánh quan trọng trên nền tảng lưu trữ Git của bạn.

Chủ đề

Liên quan