Làm thế nào để xóa commit đã push?

Làm thế nào để xóa commit đã push?

Tin ngắn hàng ngày dành cho bạn
  • Lại có thêm một công cụ hỗ trợ tìm kiếm nhanh lịch sử gõ lệnh nè mọi người: atuinsh/atuin.

    Điều thú vị là nó dùng SQLite để lưu trữ. Ngoài ra còn cung cấp tính năng đồng bộ hóa (mã hóa) hoàn toàn lịch sử giữa các máy với nhau nữa. Hay ghê 🤓

    » Xem thêm
  • Mình thấy ấn tượng với mô hình gemma-3n-E4B của nhà Google ghê. Đây là một trong những mô hình hứa hẹn mang các mô hình ngôn ngữ lớn xuống chạy trên thiết bị di dộng hoặc web hoặc nhúng (embedded)...

    Cảm giác nó hiểu lời nhắc hơn á, tại vì mình thử nhiều mô hình ít tham số mà nó hay lơ đi lời nhắc của mình. Ví dụ bảo: "Chỉ trả về câu trả lời, không cần giải thích gì thêm" thì rất nhiều cái vẫn cứ phải chêm vào câu mở đầu, giải thích... còn với gemma-3n thì trả lời rất đúng trọng tâm.

    » Xem thêm
  • Trước là sử dụng CSS để tạo hiệu ứng "loading", còn giờ có thể chỉ cần mỗi 1 tệp svg cũng "loading" được luôn: svg-loaders

    » Xem thêm

Vấn đề

Có một từ khoá thấy rất nhiều người tìm kiếm đó là "xóa commit đã push". Tình cờ thay, trước đó tôi viết một bài có tên là Tôi vừa lỡ commit sai, làm sao để sửa lại ngay lập tức?. Bài viết này lại lọt vào kết quả tìm kiếm top đầu trên Google, nhưng điều đáng nói là nội dung không nhắc đến cách giải quyết vấn đề mọi người đang gặp phải, mà chỉ đơn giản là hướng dẫn bạn xóa commit "chưa" push.

Vì thế để tránh nhầm lẫn, đồng thời giúp bạn đọc có giải pháp chính xác hơn trong vấn đề này. Bài viết ngày hôm nay chúng ta hãy cùng nhau tìm hiểu xem làm cách nào để xóa commit đã push nhé!

Hiểu bản chất để xoá

Trong suốt thời gian làm việc, đôi khi nghe nhiều người hay nói git khá "dễ" học, hoặc tự tin "khoe" kỹ năng sử dụng thành thạo git của họ. Thành thật mà nói đối với tôi, git là một thứ gì đó rất khó mà bản thân chỉ có thể sử dụng nó ở mức trung bình. Tức là biết cách sử dụng các lệnh cơ bản như init, clone, pull, push, branch... và một số lệnh khác khi làm việc nhóm. Thực tế git cung cấp rất nhiều câu lệnh cùng với nhiều tuỳ chọn khác nữa, vẫn là push nhưng kèm với nó là nhiều tuỳ chọn (options) mà chưa bao giờ dùng tới vì không biết công dụng của nó. Đấy là còn chưa kể đến githooks - một tính năng nâng cao trong git. Nhiều lệnh nâng cao của git phải nói là chưa biết đến sự tồn tại, rất khó hiểu và nhiều khả năng phù hợp cho các dự án lớn, các dự án phức tạp. Mỗi người, nhóm, tổ chức lại có một quy trình làm việc bằng git riêng, cho nên điều đó cũng góp phần tạo nên sự đa dạng trong cách sử dụng git.

Quay trở lại với vấn đề, tạm quên những thứ phức tạp ở trên đi. Về bản chất, một khi bạn đã push commit lên remote rồi thì khả năng để xóa commit đó khá là rủi ro. Chưa cần biết đến mục đích xóa là gì. Xoá do commit vô nghĩa? Xoá do commit sai nên xóa đi cho đẹp git tree? Hay chỉ đơn giản là thích thì xoá!? Tưởng chừng đơn giản nhưng hoá ra lại rất phức tạp.

Hãy hình dung git sinh ra là dành cho quy trình làm việc nhóm, phân tán. Mỗi commit được push lên như một cam kết thay đổi mã. Có người pull về, họ tiếp tục viết thêm mã vào và lại đẩy lên. Giả sử là bạn có thể xóa được commit bất kì đi thì chẳng phải sẽ gây ra một sự xáo trộn mã ghê ghớm hay sao? Dòng mã đó đã tồn tại trong các commit sau đó, nếu ai đó đã chỉnh sửa vào đoạn mã mà bạn muốn xoá thì chẳng phải chúng ta sẽ trải qua một quá trình rebase từ thời điểm xoá điện hiện tại? Quả là một cơn ác mộng.

Lúc này, bạn sẽ phải từ bỏ hy vọng xóa bất kì commit đã push nào đi, vì git không khuyến khích làm điều đó. Nhưng nếu muốn xóa các commit cuối cùng thì vẫn có khả năng làm được với rủi ro tối thiểu.

Có thể bạn sẽ thấy một khoảng "thời gian vàng" để có thể xóa các commit cuối mà không gây ảnh hưởng đến ai đó, chính là push lên rồi nhưng chưa ai pull về. Như vậy chúng ta hoàn toàn có thể sử dụng cờ --force để push lại toàn bộ commit ở dưới local lên remote. Tất nhiên cờ --force luôn là một thứ gì đó tối kỵ mà không nên lạm dụng. Hầu hết các chương trình cung cấp cờ force đều cảnh báo hãy chắc chắn là bạn biết bạn đang làm gì. Nếu không, đừng bao giờ sử dụng. Tóm lại, có 3 trường hợp xoá commit bằng cờ --force.

Force push trên nhánh dùng chung (ví dụ như nhánh develop)

Nhánh dùng chung để ám chỉ nhánh được nhiều người tham gia phát triển, ví dụ điển hình là develop, nơi mọi người liên tục commit hoặc merge code.

Giả sử nhánh develop trên remote có commit cuối cùng là commit bạn muốn xóa, tuyệt vời, hãy tận dụng khoảng thời gian chưa ai pull về và chưa ai push bất kì thứ gì mới lên thì bạn có thể force.

# Trở về commit trước đó
$ git reset HEAD~1

# Force push lại toàn bộ commit dưới local
$ git push --force

Thế là xong, bây giờ git tree của bạn trở về y hệt như trước khi có commit cuối cùng.

Trong trường hợp commit cuối cùng không phải là của bạn nữa, lúc này chắc chắn đã có người pull commit của bạn về rồi, nếu force push thời điểm này sẽ gây ra một sự xáo trộn mã ghê ghớm, dễ thấy nhất là khả năng mất tất cả commit từ phía sau commit bạn muốn xóa.

Force push trên nhánh một mình phát triển (ví dụ như nhánh feature/feature-name)

Nhánh tính năng mà bạn đang phát triển chưa được merge vào develop, có một commit cuối cùng sai và bạn muốn xóa nó khỏi git thì lúc này có thể thoải mái sử dụng force push để đẩy lại code. Vì nhánh chỉ có một mình commit nên khả năng sẽ không có ai pull code về và push code lên. Cách làm thì cũng tương tự như trên.

# Trở về commit trước đó
$ git reset HEAD~1

# Force push lại toàn bộ commit trước đó
$ git push --force

Nếu vẫn muốn xoá một commit ở vị trí bất kỳ

Sử dụng rebase -i để chỉnh sửa số lượng commit gần nhất. Ví dụ commit muốn xoá nằm ở vị trí thứ 10.

$ git rebase -i HEAD~10
pick abc123 Commit 1
pick def456 Commit 2
...
pick ghi789 Commit 10

Sửa lại pick ở Commit 10 thành drop và lưu lại. Nếu may mắn, bạn sẽ không phải giải quyết bất kỳ xung đột nào do commit vừa xoá không có đoạn mã nào liên quan đến 9 commit trước đó. Còn nếu không, tình xuống xấu nhất là cần phải giải quyết lần lượt 9 xung đột xảy ra trong 9 commit còn lại. Đó là một cơn ác mộng!

Cuối cùng, nếu commit đã được xoá, xung đột đã được giải quyết thì vẫn cần --force để đẩy tất cả thay đổi lên remote, không quên kèm theo lời cầu nguyện cho đồng nghiệp chưa ai làm gì trên nhánh đó.

Trong git, nếu sử dụng --force để push, nó thay thế toàn bộ commit dưới local của bạn lên remote. Thế cho nên commit của người khác sau thời điểm bạn force thì sẽ "không cánh mà bay". Vì thế, một quy tắc vàng ở đây là: Chỉ force push trên nhánh một mình phát triển, còn đối với nhánh nhiều người tham gia thì không nên dùng force. Nếu vẫn quyết định dùng, hãy tập hợp mọi người lại và thảo luận cùng với họ.

Chưa kể nhiều nhóm có quy trình làm việc sử dụng Protected Branch, tức là tạo ra quy tắc để bảo vệ nhánh, ai có quyền pull, push, ai có quyền merge... Giả sử không có quyền, đồng nghĩa không có cách nào để force push, giải pháp tốt nhất khi đó là giải trình với quản lý của bạn.

Từ đầu đến giờ cứ nhắc đến force, force, force nghe mà nặng nề. Vậy ngoài cách đó ra thì còn cách nào xóa được commit không? Theo tôi được biết thì không còn cách nào cả. Commit khi còn ở dưới local thì có thể xóa theo cách trong bài viết Tôi vừa lỡ commit sai, làm sao để sửa lại ngay lập tức?, chứ một khi đã push lên rồi thì chỉ có cách force để xóa, mà đã force hãy lưu ý đến đến khả năng làm mất commit của người khác.

Nếu không muốn dùng cờ force mà vẫn muốn huỷ bỏ commit cuối cùng thì hãy thử revert lại commit trước đó. Lệnh revert tạo ra một commit mới với các thay đổi nhằm khôi phục lại những gì đã đổi ở commit trước đó. Mọi thứ sẽ trở lại như cũ, chỉ có điều bạn không thể xóa được commit đó.

$ git revert HEAD
$ git push

Cuối cùng, đây là bài viết tham khảo chứ không khuyến khích bạn đọc áp dụng vào trong thực tế. Hãy sẵn sàng chịu trách nhiệm trước những gì mà bạn sắp làm. Hãy nhớ, chỉ nên dùng --force khi biết chắc chắn rằng nó làm gì.

Tổng kết

Git được sinh ra để giải quyết vấn đề làm việc nhóm, phân tán. Mỗi commit trong git như một cam kết và rất khó để xóa được chúng nếu đã đẩy lên remote. Tuy nhiên bạn có thể thử áp dụng cách dùng cờ --force để xóa commit cuối cùng hoặc một giải pháp an toàn hơn là revert lại commit.

Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...