Câu hỏi Xóa các cam kết từ một nhánh trong Git


Tôi muốn biết cách xóa một cam kết.

Bởi delete, Ý tôi là như thể tôi không thực hiện cam kết đó, và khi tôi đẩy mạnh trong tương lai, những thay đổi của tôi sẽ không đẩy tới chi nhánh từ xa.

Tôi đọc trợ giúp git, và tôi nghĩ lệnh tôi nên sử dụng là git reset --hard HEAD. Điều này có đúng không?


2582
2017-08-27 03:39


gốc


Tôi nghĩ rằng đây là không phải một bản sao của Git hoàn tác lần commit cuối cùng vì nó hỏi làm thế nào để xóa bất kì cam kết từ một chi nhánh. Tôi cũng nghĩ rằng không có câu trả lời thực sự giải quyết câu hỏi này. Tất cả họ đều tua lại các cam kết cuối cùng, chứ không phải cherry-pick và delete một cam kết có thể xảy ra trong một thời gian trước. - Chris
@ Chris, câu trả lời với git rebase -i HEAD~10 không giải quyết câu hỏi, vì nó cho phép bạn tự ý chọn các cam kết xóa. Git áp dụng các cam kết trong phạm vi bạn chỉ định từng cái một, bỏ qua các cam kết bạn đã xóa khỏi nhật ký. Tôi đã sử dụng lệnh này ngay hôm nay để loại bỏ các cam kết gần đây nhất thứ hai và thứ ba đối với repo của tôi trong khi vẫn giữ vị trí hàng đầu. Tôi đồng ý rằng không có câu trả lời nào khác thỏa đáng. - MST
@MST có, tôi nên nói, không có các tùy chọn trong câu trả lời được chấp nhận địa chỉ câu hỏi này, nhưng bạn hoàn toàn đúng - lệnh đó dường như làm việc - Chris


Các câu trả lời:


Cẩn thận:  git reset --hard  S DEL XÓA THAY ĐỔI TRỰC TIẾP LÀM VIỆC CỦA BẠN. Chắc chắn rằng stash bất kỳ thay đổi cục bộ nào bạn muốn giữ trước khi chạy lệnh này.

Giả sử bạn đang ngồi trên cam kết đó, sau đó lệnh này sẽ wack nó ...

git reset --hard HEAD~1

Các HEAD~1 có nghĩa là cam kết trước khi đứng đầu.

Hoặc, bạn có thể xem kết quả của git log, tìm id cam kết của cam kết bạn muốn sao lưu và sau đó thực hiện việc này:

git reset --hard <sha1-commit-id>

Nếu bạn đã đẩy nó, bạn sẽ cần phải làm một lực đẩy để loại bỏ nó ...

git push origin HEAD --force

Tuy nhiên, nếu những người khác có thể đã kéo nó, thì bạn sẽ tốt hơn khi bắt đầu một chi nhánh mới. Bởi vì khi họ kéo, nó sẽ kết hợp nó vào công việc của họ, và bạn sẽ khiến nó bị đẩy lùi lại.

Nếu bạn đã đẩy, nó có thể tốt hơn để sử dụng git revert, để tạo ra một "hình ảnh phản chiếu" cam kết sẽ hoàn tác các thay đổi. Tuy nhiên, cả hai cam kết sẽ được trong nhật ký.


FYI - git reset --hard HEAD là tuyệt vời nếu bạn muốn loại bỏ WORK IN PROGRESS. Nó sẽ thiết lập lại bạn trở lại cam kết gần đây nhất, và xóa tất cả các thay đổi trong cây và chỉ số làm việc của bạn.


Cuối cùng, nếu bạn cần tìm một cam kết mà bạn "xóa", nó thường xuất hiện trong git reflog trừ khi bạn có rác thu thập kho lưu trữ của bạn.


3311
2017-08-27 03:44



HEAD~1 hoặc chỉ HEAD^. Nếu bạn đẩy, bạn nên sử dụng git revert thay thế. - Jakub Narębski
hãy chắc chắn để ngăn chặn bất kỳ thay đổi cục bộ nào bạn muốn giữ trước khi chạy lệnh này ... - William Denniss
Rõ ràng bạn cũng có thể sử dụng HEAD~n quay trở lại" n cam kết từ đầu của bạn. Có lẽ từ thời điểm này bạn có thể giải thích ... --hard HEAD cũng như HEAD~0 => xóa công việc đang tiến hành. - yoshi
@ beamrider9 imho git rebase hầu như luôn là cách tốt hơn để xóa các cam kết (như được mô tả trong câu trả lời của Greg Hewgill) - ít nhất là vì việc rebase thực tế bao gồm một cảnh báo lớn rằng bạn sẽ xóa nội dung 4realz. - Noah Sussman
điều này không xóa các thay đổi từ cây cam kết. OP yêu cầu một cam kết đã được thực hiện. nếu bạn reset --hardvà kiểm tra log --oneline --all, các cam kết vẫn còn trong cây. Làm cách nào để xóa các cam kết này khỏi cây? Cảm ơn. - iGbanam


Nếu bạn chưa đẩy cam kết ở bất cứ đâu, bạn có thể sử dụng git rebase -i để loại bỏ cam kết đó. Đầu tiên, hãy tìm hiểu xem cam kết đó là bao xa (xấp xỉ). Sau đó làm:

git rebase -i HEAD~N

Các ~N có nghĩa là rebase cuối cùng N cam kết (N phải là một số, ví dụ HEAD~10). Sau đó, bạn có thể chỉnh sửa tệp mà Git trình bày cho bạn để xóa cam kết vi phạm. Khi lưu tệp đó, Git sau đó sẽ viết lại tất cả các cam kết sau đây như thể bạn đã xóa không tồn tại.

Cuốn sách Git có tốt phần về rebasing với hình ảnh và ví dụ.

Hãy cẩn thận với điều này mặc dù, bởi vì nếu bạn thay đổi một cái gì đó mà bạn  đẩy ở nơi khác, một cách tiếp cận khác sẽ là cần thiết trừ khi bạn đang có kế hoạch để làm một lực đẩy.


603
2017-08-27 03:51



Lưu ý: Nếu bạn tình cờ có bất kỳ sự hợp nhất --no-ff nào trong đợt cam kết cuối cùng, rebase sẽ bán thịt chúng: (Điều này được đề cập dưới dạng -p trên trang này. Vấn đề là, nếu bạn thay thế -i với -p, bạn không còn nhận được rằng bật lên với sự lựa chọn cho "chỉnh sửa cam kết này, sqush rằng một", vv vv Bất cứ ai biết giải pháp? - Bukov
Nếu bạn đã đẩy nó thì sao? (chỉ cần tôi sử dụng repo từ xa) - Costa
@Costa bạn có thể sử dụng push -f để ép buộc và thay thế nhánh từ xa bằng nhánh địa phương của bạn. Nếu đó chỉ là repo từ xa của riêng bạn, không sao cả. Sự cố bắt đầu nếu ai đó khác đã tìm nạp trong thời gian chờ đợi. - Greg Hewgill
Tôi đã thêm và cam kết một tệp dữ liệu quá lớn đối với GitHub (vâng, có lẽ nó không nên ở trong repo nguồn; Khi tôi cố gắng đẩy, GitHub từ chối vì tập tin quá lớn. Tất cả những gì tôi muốn làm là hoàn tác cam kết này, đồng thời tiết kiệm một vài cam kết không liên quan khác theo sau. Các git rebase -i HEAD~5 lệnh là chính xác những gì tôi cần để loại bỏ hoàn toàn cam kết này khỏi repo địa phương của tôi! Cảm ơn! - aldo
@dumbledad: Với rebase -i, các thay đổi tương ứng với cam kết đã xóa không được giữ nguyên. - Greg Hewgill


Một khả năng khác là một trong những lệnh yêu thích cá nhân của tôi:

git rebase -i <commit>~1

Điều này sẽ bắt đầu quá trình rebase ở chế độ tương tác -i tại thời điểm ngay trước khi cam kết bạn muốn whack. Trình chỉnh sửa sẽ bắt đầu liệt kê tất cả các cam kết kể từ đó. Xóa dòng chứa cam kết bạn muốn xóa và lưu tệp. Rebase sẽ thực hiện phần còn lại của tác phẩm, chỉ xóa cam kết đó, và phát lại tất cả những người khác trở lại nhật ký.


416
2017-08-27 03:49



thx, btw nếu bạn gặp phải bất kỳ vấn đề nào (như các cam kết trống), bạn có thể sử dụng git rebase --continue - realgt
Thậm chí dễ dàng hơn: git rebase -i HEAD~1 - mmell
Wowzers. git rebase -i HEAD~1 thực sự làm sạch repo lên rất nhiều! Thật khó để nói chính xác những gì nó đã làm, nhưng toàn bộ điều trông rất nhiều neater. Một chút đáng báo động, thực sự. - Charles Wood
Tôi nghĩ rằng cần lưu ý rằng cam kết không bị xóa bỏ, chỉ bị xóa khỏi danh sách. Nếu bạn lộn xộn, bạn có thể lấy lại cam kết bằng cách sử dụng reflog. - Zaz
Đang xóa dòng giống như d / drop? - Leo


Tôi đang thêm câu trả lời này bởi vì tôi không thấy lý do tại sao bất kỳ ai vừa cố gắng thực hiện công việc sẽ muốn xóa tất cả công việc đó vì một số sai lầm khi sử dụng Git!

Nếu bạn muốn giữ lại công việc của mình và chỉ cần 'hoàn tác' lệnh cam kết đó (bạn bị bắt trước khi đẩy lùi lại):

git reset --soft HEAD~1

Không sử dụng --hard gắn cờ trừ khi bạn muốn hủy công việc của mình trong tiến trình kể từ lần commit cuối cùng.


281
2017-10-15 18:17



Đây là một ví dụ về lý do tại sao: bạn làm một phần nhỏ công việc trên một máy chủ phát triển mà bạn cam kết. Sau đó, nó chỉ ra rằng máy chủ đó không có truy cập HTTPS đi, vì vậy bạn không thể đẩy cam kết bất cứ nơi nào. Dễ nhất để chỉ giả vờ nó không bao giờ xảy ra, và làm lại bản vá từ máy địa phương của bạn. - Steve Bennett
reset --soft là vị cứu tinh cuộc sống không mất công việc hiện tại. - RaphaelDDL
Cảm ơn. Câu trả lời này nên được xếp hạng cao hơn hoặc đưa vào câu trả lời được chấp nhận. Xóa cam kết! = Hoàn nguyên cam kết. - Alsciende
@RandolphCarter: bạn vẫn sẽ mất bất kỳ thay đổi không được cam kết nào. - naught101
@Rob, một ví dụ là khi bạn vô tình cam kết một tệp chứa bí mật (ví dụ: mật khẩu) không bao giờ nên được kiểm soát nguồn. Cam kết cục bộ phải là bị phá hủy, không chỉ hoàn tác, vì vậy nó sẽ không bao giờ bị đẩy đến máy chủ. - Bob Meyers


Nếu bạn không xuất bản thay đổi, để xóa cam kết mới nhất, bạn có thể làm

$ git reset --hard HEAD^

(lưu ý rằng điều này cũng sẽ loại bỏ tất cả các thay đổi không được cam kết; sử dụng cẩn thận).

Nếu bạn đã xuất bản cam kết bị xóa, hãy sử dụng git hoàn nguyên

$ git revert HEAD

47
2017-08-27 10:47



Điều đó không hiệu quả. Khi tôi git đăng nhập, mọi thứ vẫn còn đó, không có vấn đề tại sao tôi làm điều đó chỉ cần thêm cam kết nhiều hơn nữa. Tôi muốn làm sạch lịch sử. - Costa
@Costa: Điều gì đã không hoạt động (tức là bạn đã sử dụng phiên bản nào), và bạn đã đăng nhập như thế nào? - Jakub Narębski
Tôi đã thử gần như tất cả mọi thứ trên Q & A này. (Tôi đã thử git hoàn nguyên HEAD, gần đây nhất) Nhật ký git của tôi: tree = log --all --graph --format=format:'%C(bold blue)%h%C(reset) %C(dim black)%s%C(reset)%C(bold red)%d%C(reset) %C(green)by %an, %ar%C(reset)' - Costa
Tôi chỉ muốn xóa các cam kết (như thể chúng chưa bao giờ tồn tại). Tôi đã đi trên một số cuộc phiêu lưu mã hóa lạ, với một số cam kết mới, và tất cả đã kết thúc được thùng rác. Làm thế nào tôi có thể xóa chúng khỏi nhật ký git của tôi? - Costa
Holy crap một cái gì đó kỳ diệu đã làm chính xác những gì tôi muốn .... mà một trong những lệnh đã làm nó? !!?! - Costa


Xóa toàn bộ cam kết

git rebase -p --onto SHA^ SHA

Rõ ràng thay thế "SHA" bằng tham chiếu bạn muốn loại bỏ. Chữ "^" trong lệnh đó là chữ.

http://sethrobertson.github.io/GitFixUm/fixup.html


43
2017-08-31 19:36



làm thế nào tôi có thể upvote thêm câu trả lời này ??? các giải pháp khác chỉ hiển thị cách thực hiện tương tác hoặc xóa các cam kết hàng đầu. - ribamar
Cảm ơn vì đường dẫn này! Tôi đã tự hỏi, sau khi chạy nó, tại sao tôi vẫn thấy SHA commit trong git reflog của tôi? - bapors
Tại sao chúng ta cần -p đây? - Serge Roussak
-p, --preserve-merges            Tạo lại các cam kết hợp nhất thay vì làm phẳng lịch sử bằng cách thực hiện lại một cam kết hợp nhất. Hợp nhất các giải pháp xung đột hoặc sửa đổi thủ công để hợp nhất các cam kết không được bảo toàn. - raittes


git reset --hard commitId

git push <origin> <branch> --force

PS: CommitId là tên mà bạn muốn hoàn nguyên về


33
2017-10-16 09:51



git push --force <origin> <branchName>. như không nhắc đến tên chi nhánh, nó có thể thay đổi tất cả các tập tin trên điều khiển từ xa. - sheelpriy


Nếu bạn muốn sửa lỗi cam kết mới nhất của mình, bạn có thể hoàn tác cam kết và unstage các tệp trong đó, bằng cách thực hiện:

git reset HEAD~1

Điều này sẽ trả về kho lưu trữ của bạn về trạng thái của nó trước khi lệnh git thêm các lệnh đã dàn dựng các tệp. Các thay đổi của bạn sẽ nằm trong thư mục làm việc của bạn. HEAD ~ 1 đề cập đến cam kết bên dưới mũi hiện tại của nhánh.

Nếu bạn muốn hủy bỏ N commit, nhưng giữ các thay đổi mã trong thư mục làm việc của bạn:

git reset HEAD~N

Nếu bạn muốn loại bỏ các cam kết mới nhất của bạn, và không muốn giữ các thay đổi mã, bạn có thể làm một "cứng" thiết lập lại.

git reset --hard HEAD~1

Tương tự như vậy, nếu bạn muốn loại bỏ N lần commit cuối cùng, và không muốn giữ các thay đổi mã:

git reset --hard HEAD~N

29
2018-05-31 07:19