Bagaimana cara membatalkan "git cherry-pick" yang sukses?

104

Di repo lokal, saya baru saja mengeksekusi git cherry-pick SHAtanpa konflik atau masalah. Saya kemudian menyadari bahwa saya tidak ingin melakukan apa yang baru saja saya lakukan. Saya belum mendorong ini ke mana pun.

Bagaimana cara menghapus cherry pick ini?

Saya ingin tahu apakah ada cara untuk melakukan ini:

  • ketika saya memiliki perubahan lokal lainnya
  • ketika saya tidak memiliki perubahan lokal lainnya

Lebih disukai dengan satu perintah untuk kedua kasus jika memungkinkan.

Brad Parks
sumber

Jawaban:

142

Pilihan ceri pada dasarnya adalah komit, jadi jika Anda ingin membatalkannya, Anda cukup membatalkan komit.

ketika saya memiliki perubahan lokal lainnya

Simpan perubahan Anda saat ini sehingga Anda dapat menerapkannya kembali setelah menyetel ulang komit.

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

ketika saya tidak memiliki perubahan lokal lainnya

$ git reset --hard HEAD^
Tim
sumber
6
Hanya sebagai tambahan pada pertanyaan dan jawaban jika Anda tidak yakin apa yang Anda pilih, Anda selalu dapat 'cherry-pick SHA --no-commit' dan tidak akan ada perubahan hanya komit yang dapat dengan mudah diperiksa , ini berguna untuk pemetikan ceri parsial
kuskmen
2
windows: git reset --hard "HEAD ^"
slim
25

Untuk membatalkan komit terakhir Anda, lakukan saja git reset --hard HEAD~.

Sunting : jawaban ini diterapkan pada versi sebelumnya dari pertanyaan yang tidak menyebutkan pelestarian perubahan lokal; jawaban yang diterima dari Tim memang benar. Terima kasih untuk qwertzguy atas perhatiannya.

David Deutsch
sumber
2
Itu seharusnya HEAD ^ or HEAD ~ 1
Andreas Wederbrand
Keduanya setara dengan HEAD ~ (dan HEAD ^ 1, dalam hal ini)
David Deutsch
1
@DavidDeutsch Itu benar (meskipun hanya di versi Git yang lebih baru), tetapi huruf besar ( HEAD) lebih kuat: pertimbangkan kasus yang tidak menguntungkan di mana headnama referensi yang ada.
jub0bs
1
@Jubobs - poin yang bagus; Saya telah mengubah casing dalam jawaban saya.
David Deutsch
1
@qwertzguy, tangkapan bagus; melihat stempel waktu, sedikit tentang perubahan lokal ditambahkan ke pertanyaan satu menit setelah saya memposting jawaban ini :)
David Deutsch
9

Jika memungkinkan, hindari hard reset. Reset keras adalah salah satu dari sedikit operasi destruktif di git. Untungnya, Anda dapat membatalkan pilihan ceri tanpa pengaturan ulang dan menghindari apa pun yang merusak.

Perhatikan hash dari cherry-pick yang ingin Anda batalkan, katakan saja ${bad_cherrypick}. Lakukan git revert ${bad_cherrypick}. Sekarang isi pohon kerja Anda seperti sebelum Anda memilih ceri yang buruk.

Ulangi git cherry-pick ${wanted_commit}, dan jika Anda senang dengan pilihan baru, lakukan a git rebase -i ${bad_cherrypick}~1. Selama rebase, hapus keduanya ${bad_cherrypick}dan pengembalian yang sesuai.

Cabang yang sedang Anda kerjakan hanya akan memiliki cherry-pick yang bagus. Tidak perlu reset!

Cuadue
sumber
7

git reflog bisa datang untuk menyelamatkanmu.

Ketik di konsol Anda dan Anda akan mendapatkan daftar riwayat git Anda bersama dengan SHA-1 yang mewakili mereka.

Cukup lakukan pembayaran SHA-1 yang ingin Anda kembalikan


Sebelum menjawab mari tambahkan beberapa latar belakang, menjelaskan apa ini HEAD.

First of all what is HEAD?

HEADhanyalah referensi ke komit saat ini (terbaru) di cabang saat ini.
Hanya boleh ada satu orang HEADpada waktu tertentu. (tidak termasuk git worktree)

Konten HEADdisimpan di dalam.git/HEAD dan berisi 40 byte SHA-1 dari komit saat ini.


detached HEAD

Jika Anda tidak berada di komit terbaru - artinya HEADmenunjuk ke komit sebelumnya dalam riwayat panggilannyadetached HEAD .

masukkan deskripsi gambar di sini

Pada baris perintah, akan terlihat seperti ini- SHA-1 sebagai ganti nama cabang karena HEADtidak mengarah ke ujung cabang saat ini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Beberapa opsi tentang cara memulihkan dari HEAD yang terlepas:


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

Ini akan memeriksa cabang baru yang menunjuk ke komit yang diinginkan.
Perintah ini akan memeriksa komit yang diberikan.
Pada titik ini, Anda dapat membuat cabang dan mulai bekerja dari titik ini.

# 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

Anda selalu dapat menggunakan reflog juga.
git reflogakan menampilkan perubahan apa pun yang memperbarui HEADdan memeriksa entri reflog yang diinginkan akan mengaturHEAD kembali ke komit ini.

Setiap kali HEAD diubah, akan ada entri baru di reflog

git reflog
git checkout HEAD@{...}

Ini akan membuat Anda kembali ke komitmen yang Anda inginkan

masukkan deskripsi gambar di sini


git reset --hard <commit_id>

"Pindahkan" HEAD Anda kembali ke komit yang diinginkan.

# 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.
  • Catatan: ( Sejak Git 2.7 )
    Anda juga dapat menggunakan file git rebase --no-autostash.

git revert <sha-1>

"Urungkan" rentang komit atau komit yang diberikan.
Perintah reset akan "membatalkan" setiap perubahan yang dibuat dalam komit yang diberikan.
Komit baru dengan tambalan urung akan dilakukan sementara komit asli juga akan tetap ada dalam riwayat.

# 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>

Skema ini menggambarkan perintah mana yang melakukan apa.
Seperti yang Anda lihat di sana, reset && checkoutmodifikasi file HEAD.

masukkan deskripsi gambar di sini

CodeWizard
sumber
mungkin menambahkangit reset --hard
wyx
4

Menghadapi masalah yang sama ini, saya menemukan jika Anda telah melakukan dan / atau mendorong ke remote sejak cherry-pick Anda berhasil, dan Anda ingin menghapusnya, Anda dapat menemukan SHA cherry-pick dengan menjalankan:

git log --graph --decorate --oneline

Kemudian, (setelah menggunakan :wquntuk keluar dari log) Anda dapat menghapus cherry-pick menggunakan

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

dimana YOUR_SHA_HERE sama dengan komit yang dipilih ceri 40- atau disingkat SHA 7 karakter.

Pada awalnya, Anda tidak akan dapat mendorong perubahan Anda karena repo jarak jauh dan repo lokal Anda akan memiliki riwayat komit yang berbeda. Anda dapat memaksa komit lokal Anda untuk mengganti apa yang ada di remote Anda dengan menggunakan

git push --force origin YOUR_REPO_NAME

(Saya mengadaptasi solusi ini dari Seth Robertson : Lihat "Menghapus seluruh komit.")

brogrammer
sumber
1

Satu perintah dan tidak menggunakan git resetperintah destruktif :

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

Itu hanya menjatuhkan komit, menempatkan Anda kembali tepat sebelum pilihan ceri bahkan jika Anda memiliki perubahan lokal.

qwertzguy.dll
sumber
Itu hanya menjatuhkan komit. apa menurutmu git reset HEAD^?
Tim
@TimCastelijns git resetmembatalkan tindakan komit tanpa menghilangkan perubahan apa pun. Saya sarankan Anda membaca git-scm.com/docs/git-reset . Pertanyaan dari OP adalah membatalkan pilihan ceri. Cobalah kedua perintah tersebut, perintah saya akan mengembalikan Anda ke keadaan yang sama seperti sebelum memilih ceri. git resetakan mengacaukan pohon kerja Anda karena meninggalkan perubahan yang dipetik ceri dan menjadi tidak bisa dibedakan dari perubahan lokal Anda yang sudah ada sebelumnya.
qwertzguy
ya, maaf, maksud saya reset --hard. Tidak ada perubahan
Tim
1
@TimCastelijns git reset --hardadalah perintah destruktif yang akan menghapus perubahan lokal yang tidak terkait juga dan akan melakukannya dengan cara yang tidak dapat dipulihkan! Jadi bukan itu yang diminta OP.
qwertzguy
2
Jawaban ini akan jauh lebih berguna jika Anda menjelaskan apa yang dilakukan sedperintah itu, apa --autostashbedanya dengan melakukannya secara manual, dan apa fungsinya.
Chris Halaman