Làm thế nào để hoàn tác một “git cherry-pick” thành công?


99

Trên một repo cục bộ, tôi vừa thực thi git cherry-pick SHAmà không có bất kỳ xung đột hoặc sự cố nào. Sau đó tôi nhận ra rằng tôi không muốn làm những gì tôi vừa làm. Tôi đã không đẩy điều này đi bất cứ đâu.

Làm thế nào tôi có thể loại bỏ chỉ hái anh đào này?

Tôi muốn biết có cách nào để làm điều này không:

  • khi tôi có những thay đổi cục bộ khác
  • khi tôi không có thay đổi cục bộ nào khác

Tốt hơn với một lệnh cho cả hai trường hợp nếu có thể.

Câu trả lời:


134

Cherry-pick về cơ bản là một cam kết, vì vậy nếu bạn muốn hoàn tác nó, bạn chỉ cần hoàn tác cam kết.

khi tôi có những thay đổi cục bộ khác

Lưu trữ các thay đổi hiện tại của bạn để bạn có thể áp dụng lại chúng sau khi đặt lại cam kết.

$ git stash
$ git reset --hard HEAD^
$ git stash pop  # or `git stash apply`, if you want to keep the changeset in the stash

khi tôi không có thay đổi cục bộ nào khác

$ git reset --hard HEAD^

6
Chỉ cần thêm vào câu hỏi và câu trả lời, nếu bạn không chắc mình đang chọn cherry gì, bạn luôn có thể 'cherry-pick SHA --no-commit' và sẽ không có thay đổi chỉ cam kết nào có thể dễ dàng kiểm tra , điều này rất hữu ích cho phần cherry-hái
kuskmen

2
cửa sổ: git reset --hard "ĐẦU ^"
mỏng

22

Để hoàn tác cam kết cuối cùng của bạn, chỉ cần thực hiện git reset --hard HEAD~.

Chỉnh sửa : câu trả lời này áp dụng cho phiên bản trước đó của câu hỏi không đề cập đến việc bảo toàn các thay đổi cục bộ; câu trả lời được chấp nhận từ Tim thực sự là câu trả lời chính xác. Cảm ơn qwertzguy vì những điều quan trọng.


2
Đó phải là HEAD ^ hoặc HEAD ~ 1
Andreas Wederbrand

Cả hai đều tương đương với ĐẦU ~ (và ĐẦU ^ 1, cho rằng vấn đề)
David Deutsch

1
@DavidDeutsch Điều đó đúng (mặc dù chỉ trong các phiên bản Git gần đây hơn), nhưng chữ hoa ( HEAD) mạnh mẽ hơn: hãy xem xét trường hợp không may headlà tên của một tham chiếu hiện có.
tưng bừng

1
@Jubobs - điểm tốt; Tôi đã thay đổi cách viết hoa trong câu trả lời của mình.
David Deutsch

1
@qwertzguy, bắt tốt; nhìn vào timestamps, các chút thông tin về thay đổi địa phương đã được bổ sung cho câu hỏi một phút sau khi tôi đăng câu trả lời này :)
David Deutsch

8

Nếu có thể, hãy tránh đặt lại khó. Đặt lại cứng là một trong số rất ít thao tác phá hủy trong git. May mắn thay, bạn có thể hoàn tác một lần chọn anh đào mà không cần đặt lại và tránh bất cứ thứ gì phá hoại.

Ghi lại hàm băm của phần chọn anh đào mà bạn muốn hoàn tác, giả sử như vậy ${bad_cherrypick}. Làm một git revert ${bad_cherrypick}. Bây giờ nội dung của cây làm việc của bạn giống như chúng trước khi bạn hái anh đào xấu.

Lặp lại của bạn git cherry-pick ${wanted_commit}, và khi bạn hài lòng với cách chọn anh đào mới, hãy làm một git rebase -i ${bad_cherrypick}~1. Trong quá trình rebase, hãy xóa cả hai ${bad_cherrypick}và hoàn nguyên tương ứng của nó.

Chi nhánh bạn đang làm việc sẽ chỉ có anh đào tốt. Không cần đặt lại!


6

git reflog có thể đến để giải cứu bạn.

Nhập nó vào bảng điều khiển của bạn và bạn sẽ nhận được danh sách lịch sử git của mình cùng với SHA-1 đại diện cho chúng.

Chỉ cần kiểm tra bất kỳ SHA-1 nào mà bạn muốn hoàn nguyên về


Trước khi trả lời, chúng ta hãy thêm một số thông tin cơ bản, giải thích đây là gì HEAD.

First of all what is HEAD?

HEADchỉ đơn giản là tham chiếu đến cam kết hiện tại (mới nhất) trên nhánh hiện tại.
Chỉ có thể có một duy nhất HEADtại bất kỳ thời điểm nào. (không bao gồm git worktree)

Nội dung của HEADđược lưu trữ bên trong .git/HEADvà nó chứa 40 byte SHA-1 của cam kết hiện tại.


detached HEAD

Nếu bạn không sử dụng lần cam kết mới nhất - nghĩa HEADlà nó trỏ đến một lần cam kết trước trong lịch sử mà nó được gọi detached HEAD.

nhập mô tả hình ảnh ở đây

Trên dòng lệnh, nó sẽ giống như thế này- SHA-1 thay vì tên nhánh vì HEADnó không trỏ đến đầu của nhánh hiện tại

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Một số tùy chọn về cách khôi phục từ HEAD bị tách rời:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Điều này sẽ kiểm tra nhánh mới trỏ đến cam kết mong muốn.
Lệnh này sẽ kiểm tra một cam kết nhất định.
Tại thời điểm này, bạn có thể tạo một nhánh và bắt đầu hoạt động từ thời điểm này.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Bạn luôn có thể sử dụng reflog.
git reflogsẽ hiển thị bất kỳ thay đổi nào đã cập nhật HEADvà kiểm tra mục nhập reflog mong muốn sẽ thiết lập HEADtrở lại cam kết này.

Mỗi khi HEAD được sửa đổi, sẽ có một mục mới trong reflog

git reflog
git checkout HEAD@{...}

Điều này sẽ đưa bạn trở lại cam kết mong muốn của bạn

nhập mô tả hình ảnh ở đây


git reset --hard <commit_id>

"Di chuyển" HEAD của bạn trở lại cam kết mong muốn.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Lưu ý: ( Kể từ Git 2.7 ),
    bạn cũng có thể sử dụng git rebase --no-autostash.

git revert <sha-1>

"Hoàn tác" phạm vi cam kết hoặc cam kết đã cho.
Lệnh đặt lại sẽ "hoàn tác" bất kỳ thay đổi nào được thực hiện trong cam kết đã cho.
Một cam kết mới với bản vá hoàn tác sẽ được cam kết trong khi cam kết ban đầu cũng sẽ vẫn còn trong lịch sử.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Lược đồ này minh họa lệnh nào thực hiện những gì.
Như bạn có thể thấy ở đó, hãy reset && checkoutsửa đổi HEAD.

nhập mô tả hình ảnh ở đây


có lẽ thêmgit reset --hard
wyx

3

Đối mặt với vấn đề tương tự này, tôi phát hiện ra nếu bạn đã cam kết và / hoặc đẩy sang điều khiển từ xa kể từ khi bạn hái anh đào thành công và bạn muốn xóa nó, bạn có thể tìm SHA của hái anh đào bằng cách chạy:

git log --graph --decorate --oneline

Sau đó, (sau khi sử dụng :wqđể thoát khỏi nhật ký), bạn có thể xóa cherry-pick bằng cách sử dụng

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

Ở đâu YOUR_SHA_HERE bằng với SHA gồm 40 ký tự hoặc viết tắt 7 ký tự của cam kết hái quả anh đào.

Lúc đầu, bạn sẽ không thể đẩy các thay đổi của mình vì repo từ xa và repo cục bộ của bạn sẽ có lịch sử cam kết khác nhau. Bạn có thể buộc các cam kết cục bộ của mình thay thế những gì trên điều khiển từ xa của bạn bằng cách sử dụng

git push --force origin YOUR_REPO_NAME

(Tôi đã điều chỉnh giải pháp này từ Seth Robertson : Xem "Xóa toàn bộ cam kết".)


1

Một lệnh và không sử dụng git resetlệnh hủy :

GIT_SEQUENCE_EDITOR="sed -i 's/pick/d/'" git rebase -i HEAD~ --autostash

Nó chỉ đơn giản là giảm cam kết, đưa bạn trở lại chính xác trạng thái trước khi chọn anh đào ngay cả khi bạn có những thay đổi cục bộ.


Nó chỉ đơn giản là bỏ cam kết. bạn nghĩ git reset HEAD^
Tim

@TimCastelijns git resethoàn tác hành động cam kết mà không bỏ bất kỳ thay đổi nào. Tôi khuyên bạn nên đọc git-scm.com/docs/git-reset . Câu hỏi từ OP là hoàn tác một lựa chọn anh đào. Hãy thử cả hai lệnh, của tôi sẽ đưa bạn trở lại trạng thái chính xác như trước khi hái quả anh đào. git resetsẽ làm xáo trộn cây làm việc của bạn khi nó để lại những thay đổi đã chọn và chúng trở nên không thể phân biệt được với những thay đổi cục bộ đã có từ trước của bạn.
qwertzguy

vâng, xin lỗi, ý tôi là reset --hard. Nó để lại không có thay đổi
Tim

1
@TimCastelijns git reset --hardlà một lệnh phá hủy cũng sẽ xóa các thay đổi cục bộ không liên quan và sẽ làm như vậy theo cách không thể khôi phục! Vì vậy, đó không phải là những gì OP yêu cầu.
qwertzguy

2
Câu trả lời này sẽ hữu ích hơn nhiều nếu bạn giải thích sedlệnh đó đang làm gì, điều đó khác với thực hiện thủ công như thế nào và tác dụng của lệnh --autostashđó.
Chris Page
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.