Saya perlu memunculkan dan membuang komit "tengah" di cabang master saya. Bagaimana saya bisa melakukannya?

96

Misalnya, di cabang master berikut, saya perlu membuang hanya commit af5c7bf16e6f04321f966b4231371b21475bc4da, yang merupakan yang kedua karena rebase sebelumnya:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <[email protected]>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <[email protected]>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

Saya perlu menjaga

  • Komit pertama 60b413512e616997c8b929012cf9ca56bf5c9113,
  • Komit ketiga e6523efada4d75084e81971c4dc2aec621d45530 dan
  • Komit Terakhir 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

"membuang" hanya komit Kedua af5c7bf16e6f04321f966b4231371b21475bc4da

Bagaimana saya bisa melakukan itu? Terima kasih sebelumnya Luca

Luca G. Soave
sumber

Jawaban:

103

Rebase atau pulihkan adalah opsinya. Rebase akan benar-benar menghapus komit dari riwayat sehingga akan terlihat seperti komit kedua itu tidak pernah ada. Ini akan menjadi masalah jika Anda telah mendorong cabang master ke repositori lain. Jika Anda mencoba untuk mendorong setelah rebase dalam kasus ini, git akan memberi Anda kesalahan penolakan penggabungan maju-cepat .

Kembalikan adalah solusi yang tepat ketika cabang telah dibagikan dengan repo lain. git revert af5c7bf16akan membuat komit baru yang membalikkan perubahan yang diperkenalkan oleh af5c7bf16. Dengan cara ini riwayat tidak ditulis ulang, Anda menyimpan catatan kesalahan yang jelas, dan repo lain akan menerima dorongan.

Berikut cara yang bagus untuk menghapus: git rebase -i <commit>^ Itu membawa Anda ke komit tepat sebelum yang ingin Anda hapus. Editor interaktif akan menampilkan daftar semua komitmen kembali ke titik itu. Anda dapat memilih, menekan, dll. Dalam kasus ini, hapus baris untuk komit yang ingin Anda hapus dan simpan file. Rebase akan menyelesaikan pekerjaannya.

JCotton
sumber
2
Jika saya akan memilih Rebase, apa komitmen yang tepat untuk melakukan rebase? Aku harus berhenti sebentar ...
Luca G. Soave
@ BBJ3 Lihat jawaban mipadi.
Prajwal Dhatwalia
34

Jika rebase adalah sebuah opsi, Anda dapat melakukan rebase dan menjatuhkannya:

$ git rebase -i 414ceffc^

Jika rebase bukan pilihan, Anda bisa mengembalikannya:

$ git revert af5c7bf16
mipadi
sumber
jika saya mendapatkan "git rebase 414ceffc" yang merupakan commit keempat yang lebih tua, bukankah saya juga akan kehilangan e6523 ketiga dan 60b41 pertama?
Luca G. Soave
3
@ Luca G. Soave: Anda hanya "kehilangan" sebuah komit jika Anda secara khusus menyuruh git rebaseuntuk menjatuhkannya (dengan menjalankan rebasedalam mode interaktif dan menghapus entri tersebut).
mipadi
Terima kasih mipadi, saya memberikan suara saya kepada JCotton pada dasarnya untuk penjelasan yang luas bahkan jika kalian berdua, mengatakan hal yang sama ... terima kasih lagi.
Luca G. Soave
30

Terlepas dari semua pujian yang diterima jawaban asli di sini, saya tidak menemukan jawaban yang memuaskan untuk pertanyaan itu. Jika Anda menemukan diri Anda dalam situasi di mana Anda perlu menghapus komit, atau kumpulan komit dari tengah riwayat, inilah yang saya sarankan:

  • Buat cabang baru dari kepala yang berisi semua komit dan beralih ke sana.
  • Kembalikan cabang baru kembali ke titik Anda ingin memulai basis baru.
  • Kemudian, (inilah poin kuncinya) cherry memilih komit berikutnya yang sebenarnya ingin Anda terapkan setelah itu dari cabang asli ke yang baru, dan lewati komit yang tidak Anda inginkan lagi (yaitu yang Anda hapus).
  • Jika diinginkan, ganti nama cabang asli menjadi sesuatu yang menunjukkan itu kode lama, dan kemudian ganti nama cabang baru Anda dengan yang asli.
  • Terakhir, dorong perubahan Anda ke repo jarak jauh Anda (jika menggunakannya). Anda mungkin perlu menggunakan "dorongan paksa". Jika kolaborator Anda memiliki masalah dalam menarik revisi, mungkin paling mudah bagi mereka untuk menggandakan repo lagi dari sumber jarak jauh. Dengan satu atau lain cara, Anda mungkin ingin berbicara dengan mereka jika Anda merobek komitmen di tengah-tengah sejarah Anda!

Berikut info tentang Memetik Ceri: Apa arti dari memetik ceri dengan git?

Berikut beberapa cara melakukannya dengan Tortoise Git (seperti yang baru saja saya lakukan). Pasti lebih mudah menggunakan utilitas gui untuk operasi semacam ini! Petik ceri menggunakan TortoiseGit

BuvinJ
sumber
6
Ini seharusnya menjadi jawaban teratas!
MadOgre
Cara yang bagus untuk menggunakan cherry pick, solusi ini bahkan lebih baik jika Anda ingin "melewati" lebih dari satu commit.
Johnny Willer
Tidak benar-benar menjawab pertanyaan awal. Sementara solusi yang disarankan berfungsi, itu jauh lebih memakan waktu / canggung dan IMO tidak membawa manfaat apa pun. Jika cabang sudah didorong (dan digunakan di alam liar) strategi pengembalian mungkin adalah jawabannya. Jika tidak, rebase interaktif dan hapus komit yang melanggar adalah apa yang akan saya gunakan. Jika itu didorong tetapi kami tahu itu tidak digunakan oleh siapa pun, Anda masih bisa lolos dengan rebase diikuti dengan dorongan paksa.
raduw