Bagaimana cara "membatalkan pengembalian" komit Git yang dikembalikan?

486

Mengingat perubahan yang telah dilakukan menggunakan commit, dan kemudian menggunakan kembali revert, apa cara terbaik untuk membatalkan pemulihan itu?

Idealnya, ini harus dilakukan dengan komit baru, agar tidak menulis ulang sejarah.

JimmidyJoo
sumber
@ phuclv komentar untuk kemungkinan duplikat di sana, tunjukkan di sini. Satu harus ditandai asli dan satu lagi harus ditandai duplikat
John Demetriou
@JohnDemetriou tidak ada pertanyaan yang memiliki set jawaban yang lebih baik harus tetap terbuka. Waktu tidak relevan di sini. Bagaimana seharusnya pertanyaan rangkap ditangani?
phuclv
Saya tidak mengatakan tentang waktu. Saya kebetulan mengomentari salah satu dari keduanya tentang masalah ini
John Demetriou

Jawaban:

385

Jika Anda belum mendorong perubahan itu, git reset --hard HEAD^

Kalau tidak, mengembalikan reverting baik-baik saja.

Cara lain adalah dengan git checkout HEAD^^ -- .dan kemudian git add -A && git commit.

Adam Dymitruk
sumber
8
Perhatikan bahwa jika Anda ingin membatalkan kembalikan tanpa segera menerapkan perubahan asli ke cabang master, Anda dapat (1) mengembalikan cabang asli jika dihapus, (2) klik "kembalikan" pada cabang kembalikan seperti dicatat oleh Adam, lalu ( 3) klik "edit" di header PR yang dihasilkan dan ubah cabang target menjadi cabang asli alih-alih master. Sekarang cabang asli Anda dapat digabung kembali untuk mempengaruhi perubahan yang sebelumnya dikembalikan.
pauljm
1
Harap dicatat ini akan menghapus semua perubahan pada pohon dan indeks kerja. Gunakan simpanan git untuk menyimpan perubahan yang tidak akan hilang.
zpon
3
Apa kelebihan metode checkout && commit? Tampaknya dalam kasus umum git cherry-pickatau sebagai alternatif git revertadalah cara yang paling mudah untuk mengembalikan sebuah pemulihan.
Robert Jack Will
5
Saya pikir akan sangat membantu untuk menunjukkan caranya:, Otherwise, reverting the revert is perfectly fine.dan kemudian juga menjelaskan apa yang git checkout HEAD^^ -- .sedang dilakukan.
Todd
3
Tuan yang baik, jangan gunakan git add -A... kecuali jika Anda ingin menambahkan setiap file ke kontrol versi, yang kemungkinan besar tidak apa yang Anda inginkan.
Kaitain
474

git cherry-pick <original commit sha>
Akan membuat salinan komit asli, pada dasarnya menerapkan ulang komit

Mengembalikan revert akan melakukan hal yang sama, dengan pesan komit yang berantakan:
git revert <commit sha of the revert>

Salah satu dari cara-cara ini akan memungkinkan Anda untuk git pushtanpa menimpa riwayat, karena itu menciptakan komit baru setelah pengembalian.
Saat mengetik komit sha, Anda biasanya hanya membutuhkan 5 atau 6 karakter pertama:
git cherry-pick 6bfabc

Stephan
sumber
61
Ini adalah solusi paling mudah dan elegan untuk pertanyaan OPs. Jauh lebih baik daripada jawaban yang diterima dengan asumsi tentang komit revert berada di KEPALA pohon komit. Op juga secara khusus meminta solusi yang tidak menulis ulang sejarah sehingga solusi keras yang ditawarkan dalam jawaban yang diterima benar-benar salah.
Timo
6
@Timo Untuk memperjelas, jawaban yang diterima berisi solusi yang saya gunakan ("reverting the revert"), dan diposting dalam beberapa jam setelah pertanyaan saya - jelas 3 tahun lebih awal dari jawaban ini. Karenanya, tanda centang.
JimmidyJoo
6
@JimmidyJoo Saya tahu saya terlambat 3 tahun, saya hanya ingin orang datang ke sini dari pencarian google untuk melihat jawaban yang lebih baik
Stephan
2
@Stephan Yep, tapi sekali lagi, untuk memperjelas - ini adalah jawaban yang lebih baik, bukan yang saya gunakan untuk menyelesaikan masalah saya. Saya hanya mengomentari mengapa tanda centang ada di mana. Pertanyaan untuk semua: apakah konvensi SO mendikte bahwa saya harus "mempertahankan" pertanyaan saya sebelumnya dan menetapkan kembali tanda centang sebagai jawaban baru masuk?
JimmidyJoo
3
@JimmidyJoo Saya tidak tahu tentang konvensi SO. Tetapi sebagai pencari google, saya benar-benar lebih suka melihat jawaban yang lebih baik diperiksa. Dan akan menghargai upaya siapa pun untuk mempertahankan pertanyaan masa lalu mereka.
Paiman Roointan
30

Revert commit sama seperti commit lainnya di git. Artinya, Anda dapat mengembalikannya, seperti pada:

git revert 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746

Itu jelas hanya masuk akal setelah perubahan didorong, dan terutama ketika Anda tidak bisa memaksa mendorong ke cabang tujuan (yang merupakan ide bagus untuk cabang master Anda ). Jika perubahan belum didorong, lakukan saja cherry-pick, kembalikan, atau cukup hapus komit pengembalian sesuai kiriman lainnya.

Di tim kami, kami memiliki aturan untuk menggunakan revert on Revert commit yang dilakukan di cabang utama, terutama untuk menjaga sejarah tetap bersih, sehingga Anda dapat melihat commit mana yang mengembalikan apa:

      7963f4b2a9d   Revert "Revert "OD-9033 parallel reporting configuration"
      "This reverts commit a0e5e86d3b66cf206ae98a9c989f649eeba7965f.
                    ...
     a0e5e86d3b6    Revert "OD-9055 paralel reporting configuration"
     This reverts commit 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746.
                ...
     Merge pull request parallel_reporting_dbs to master* commit 
    '648d7d808bc1bca6dbf72d93bf3da7c65a9bd746'

Dengan cara ini, Anda dapat melacak sejarah dan mencari tahu keseluruhan cerita, dan bahkan mereka yang tidak memiliki pengetahuan tentang warisan dapat mengatasinya sendiri. Sedangkan, jika Anda memilih atau mengganti barang, informasi berharga ini hilang (kecuali Anda memasukkannya dalam komentar).

Jelas, jika suatu komit dikembalikan dan dipulihkan kembali lebih dari sekali, itu menjadi sangat berantakan.

Nestor Milyaev
sumber
14

Mengembalikan revert akan melakukan trik

Sebagai contoh,

Jika abcdefadalah komit dan ghijklkomit yang Anda miliki saat mengembalikan komit abcdef, jalankan:

git revert ghijkl

Ini akan mengembalikan revert

rafee_que_
sumber
4

Ini terlihat bodoh bagi saya. Tetapi saya telah berada dalam situasi yang sama dan saya kembali untuk komitmen yang dikembalikan. Saya melakukan number reverts jadi saya harus melakukan revert untuk setiap 'reit commit'.

Sekarang sejarah komit saya terlihat sedikit aneh.

sejarah yang aneh

Ini adalah proyek kesayangan jadi tidak masalah. Tetapi untuk proyek kehidupan nyata saya akan memberikan preferensi untuk pergi ke komit terakhir sebelum mengembalikan semua kode yang dikembalikan bersama dalam satu komit dan komentar yang lebih masuk akal.

RredCat
sumber
4
Anda mungkin tertarik pada jawaban atas pertanyaan saya yang lain: stackoverflow.com/questions/10415565/…
JimmidyJoo
2
Anda dapat menghindari komit otomatis dan memilih komit yang Anda gunakan menggunakan --no-commit flag ketika kembali dan kemudian berkomitmen dengan pesan yang relevan
David Barda
Anda juga dapat menentukan beberapa id komit saat menggunakan git revert (menurut saya harus berada dalam urutan yang benar).
Aalex Gabi
Bisakah saya melakukannya dari desktop github?
Guillaume F.
4

Begini cara saya melakukannya:
Jika cabang my_branchnamedimasukkan dalam gabungan yang bisa dipulihkan. Dan saya ingin membatalkan my_branchname:

Saya pertama kali melakukan git checkout -b my_new_branchnamedari my_branchname.
Lalu saya melakukan di git reset --soft $COMMIT_HASHmana $COMMIT_HASHhash komit dari komit tepat sebelum komit pertama my_branchname(lihat git log)
Kemudian saya membuat komit baru git commit -m "Add back reverted changes"
Kemudian saya mendorong cabang baru git push origin new_branchname
Lalu saya membuat permintaan tarik untuk cabang baru.

Drew LeSueur
sumber
Cara untuk pergi ketika ada terlalu banyak "cherry-pick" untuk dilakukan. Saya tidak mengerti mengapa jawaban ini memiliki sedikit
upvote
2

Atau Anda bisa git checkout -b <new-branch>dan git cherry-pick <commit>sebelum ke dan git rebaseuntuk menjatuhkan revertkomit. kirim permintaan tarik seperti sebelumnya.

Ryan Chou
sumber
1

Jika Anda tidak menyukai gagasan "reverting a revert" (terutama ketika itu berarti kehilangan informasi riwayat untuk banyak komit), Anda selalu dapat menuju ke dokumentasi git tentang "Reverting a faulty merger" .

Diberikan situasi awal sebagai berikut

 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E   <-- fixed-up topic branch

(W adalah pengembalian awal Anda dari gabungan M; D dan E adalah perbaikan untuk cabang fitur yang awalnya rusak / komit)

Anda sekarang dapat memutar ulang komit ke A, sehingga tidak satupun dari mereka "milik" gabungan yang dikembalikan:

$ git checkout E
$ git rebase --no-ff P

Salinan baru dari cabang Anda sekarang dapat digabungkan masterlagi:

   A'---B'---C'------------D'---E'  <-- recreated topic branch
  /
 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E
NobodysNightmare
sumber
Ide bagus dan terima kasih atas tautan dokumen. Kami biasanya rebase dengan master sebelum bergabung kembali, tetapi git kemudian tampaknya menyadari bahwa A ', B', C 'sama dengan yang sebelumnya, dan saya sekarang memiliki D, E setelah W ( pastebin ). Saran tentang cara mengatasi ini?
Kristoffer Bakkejord
0

Untuk mendapatkan kembali perubahan yang tidak dipentaskan dan dipentaskan yang dikembalikan setelah komit:

git reset HEAD@{1}

Untuk memulihkan semua penghapusan yang tidak bertahap:

git ls-files -d | xargs git checkout --
Richa Goyal
sumber