Bagaimana cara mengembalikan komit gabungan yang sudah didorong ke cabang jauh?

962

git revert <commit_hash>sendirian tidak akan berhasil. -mharus ditentukan, dan saya cukup bingung tentang hal itu.

Adakah yang pernah mengalami ini sebelumnya?

Yaz
sumber
3
Lihatlah jawaban untuk pertanyaan ini: stackoverflow.com/questions/2318777/…
eugen
2
Terkait: Undo a Git merge? .
Tautan di sini adalah contoh terbaik yang menggambarkan pengembalian komit gabungan: christianengvall.se/undo-pushed-merge-git
SK Venkat
Ini adalah contoh di mana desain gittidak cocok dengan git-flowalur kerja -ish yang digunakan semua orang. Jika Anda telah developmemeriksa, tentu saja Anda ingin mengembalikan cabang fitur 2-komit yang memperkenalkan bug dan bukan cabang dev yang lama dibagikan. Terasa konyol karena harus memetiknya -m 1.
pkamb
2
Hanya satu saran lain yang tidak pernah terpikir oleh saya sebelumnya - jika salah satu dari daftar komitmen cabang kecil, Anda mungkin merasa lebih nyaman untuk mengembalikan komitmen individu daripada seluruh cabang komitmen.
Sridhar Sarnobat

Jawaban:

1153

The -mpilihan menentukan nomor induk . Ini karena komit gabungan memiliki lebih dari satu induk, dan Git tidak tahu secara otomatis induk mana yang menjadi arus utama, dan induk mana yang merupakan cabang yang ingin Anda batalkan gabungan.

Saat Anda melihat komit gabungan dalam output dari git log, Anda akan melihat orang tuanya terdaftar di baris yang dimulai dengan Merge:

commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <[email protected]>
Date:   Wed Aug 17 22:49:41 2011 +0100

Merge branch 'gh-pages'

Conflicts:
    README

Dalam situasi ini, Anda git revert 8f937c6 -m 1akan mendapatkan pohon seperti sebelumnya 8989ee0, dan git revert -m 2akan mengembalikan pohon seperti sebelumnya 7c6b236.

Untuk lebih memahami ID induk, Anda dapat menjalankan:

git log 8989ee0 

dan

git log 7c6b236
Ben James
sumber
127
dari dua angka 8989ee0, 7c6b236yang satu untuk pergi. Bagaimana saya bisa mengerti?
Arup Rakshit
12
Setelah kembali, saya tidak berpikir seseorang akan dapat dengan mudah memperbaiki kode di cabang sumber dan bergabung lagi? kernel.org/pub/software/scm/git/docs/howto/…
IsmailS
10
Saat mencari-cari penjelasan yang lebih baik di Google, saya menemukan artikel ini yang saya pikir telah melakukan pekerjaan yang baik untuk membahas rinciannya. Saya menemukan setelah membaca bahwa apa yang sebenarnya saya cari adalah perintah RESET, diikuti oleh dorongan kekuatan. Mungkin itu akan membantu orang lain. atlassian.com/git/tutorials/…
Funktr0n
46
@ArupRakshit jika Anda menjalankan git log 8989ee0dan git log 7c6b236, Anda harus tahu jawabannya.
BMW
4
log git --merges untuk melihat semua penggabungan dan git log --tidak ada gabungan untuk melihat sejarah tanpa merger. Menggabungkan cabang membawa sejarah cabang yang digabungkan ke dalam target dan membuatnya sulit untuk menggunakan log git biasa
Alex Punnen
370

Berikut ini adalah contoh lengkap dengan harapan dapat membantu seseorang:

git revert -m 1 <commit-hash> 
git push -u origin master

Di mana <commit-hash>hash komit dari penggabungan yang ingin Anda kembalikan, dan seperti yang dinyatakan dalam penjelasan jawaban ini , -m 1menunjukkan bahwa Anda ingin kembali ke pohon induk pertama sebelum penggabungan.

The git revert ...garis dasarnya melakukan perubahan sedangkan baris kedua membuat perubahan masyarakat dengan mendorong mereka ke cabang terpencil.

Sahid
sumber
21
Saya percaya git revertperintah sudah melakukan objek commit yang dibuat. Agar itu tidak terjadi, Anda harus memasukkan --no-commitbenderanya
Delfic
2
Seperti yang disebutkan @Delfic, komit sudah dikelola oleh baris pertama (saya membutuhkan: wq untuk memvalidasinya) sehingga baris kedua tidak diperlukan.
eka808
1
ini membingungkan. hanya ada 2 baris dan tidak ada git commit .. bisa seseorang tolong edit.
Jay Random
176

Ben telah memberi tahu Anda cara mengembalikan komit gabungan, tetapi sangat penting bagi Anda untuk menyadari hal itu

"... menyatakan bahwa Anda tidak akan pernah menginginkan perubahan pohon yang dibawa oleh penggabungan. Akibatnya, penggabungan nanti hanya akan membawa perubahan pohon yang diperkenalkan oleh komit yang bukan merupakan leluhur dari penggabungan yang sebelumnya dipulihkan. Ini mungkin atau mungkin tidak apa yang Anda inginkan. " (git-merge halaman manual) .

Pesan artikel / milis yang ditautkan dari halaman manual menjelaskan mekanisme dan pertimbangan yang terlibat. Pastikan Anda mengerti bahwa jika Anda mengembalikan komit penggabungan, Anda tidak bisa hanya menggabungkan cabang lagi nanti dan mengharapkan perubahan yang sama akan kembali.

Ryan Stewart
sumber
81
Tetapi Anda dapat mengembalikan revert untuk mendapatkannya kembali jika benar-benar diperlukan.
dalore
5
Terima kasih. Sangat berguna untuk diketahui sebagai kasus penggunaan untuk membatalkan penggabungan - karena bug, katakan - dan kemudian menggabungkan kembali seluruh cabang setelah bug diperbaiki, adalah yang umum.
Komponen 10
3
Jika Anda seperti saya dan kemudian memang ingin penggabungan, Anda dapat mengembalikannya, atau memilih perubahan yang Anda kembalikan.
UnitasBrooks
Dalam situasi saya, saya menekan keharusan untuk 'memulihkan kembali' untuk mendapatkan perubahan-kembali-masalah saya. Memetik ceri bisa menjadi cara yang lebih rapi? Saya akan mencobanya lain kali ...
Steven Anderson
79

Anda dapat mengikuti langkah-langkah ini untuk mengembalikan komit yang salah atau mengatur ulang cabang jarak jauh Anda kembali ke HEAD yang benar.

  1. checkout cabang jarak jauh ke repo lokal.
    git checkout development
  2. salin hash komit (yaitu id dari komit segera sebelum komit yang salah) dari git log git log -n5

    keluaran:

    komit 7cd42475d6f95f5896b6f02e902efab0b70e8038 "Gabungkan cabang 'salah-komit' menjadi 'pengembangan'"
    komit f9a734f8f44b0b37ccea769b9a2fd774c0f0c012 "ini adalah salah komit"
    komd, apakah ini benar?

  3. atur ulang cabang ke hash komit yang disalin pada langkah sebelumnya
    git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)

  4. jalankan git statusuntuk menunjukkan semua perubahan yang merupakan bagian dari komit yang salah.
  5. jalankan saja git reset --harduntuk mengembalikan semua perubahan itu.
  6. dorong paksa cabang lokal Anda ke jarak jauh dan perhatikan bahwa riwayat komit Anda bersih seperti sebelum tercemar.
    git push -f origin development
ssasi
sumber
4
bagaimana jika sementara itu 20 pengembang menarik gabungan dev terbaru?
Ewoks
2
Saya tidak akan memaksakan mendorong cabang pengembangan ketika ada 20 pengembang di tim menggunakan cabang itu. :) Dalam hal ini, adalah bijaksana untuk hanya melakukan commit revert.
ssasi
4
Ini adalah solusi yang sangat bagus ketika Anda bekerja sendiri atau Anda yakin tidak ada pengembang lain yang menarik komitmen yang Anda buat kacau
Kyle B
52
git revert -m 1 <merge-commit>
Neeraj Kumar
sumber
2
Jawaban ini tidak memiliki banyak detail. Mungkin itu sebabnya itu baik.
Gustavo Straube
30

Untuk menjaga log tetap bersih karena tidak ada yang terjadi (dengan beberapa kelemahan dengan pendekatan ini (karena push -f)):

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>

'commit-hash-before-merge' berasal dari log (git log) setelah penggabungan.

nvd
sumber
Petunjuk: Jika Anda melakukan ini di perusahaan Anda, Anda mungkin tidak memiliki izin.
eneski
3
tidak pernah melakukan push -frepo bersama
Baptiste Mille-Mathias
17

Terkadang cara paling efektif untuk mengembalikan adalah dengan mundur dan mengganti.

git log

Gunakan hash komit ke-2 (hash penuh, yang ingin Anda kembalikan ke, sebelum kesalahan terdaftar) dan kemudian rebranch dari sana.

git checkout -b newbranch <HASH>

Kemudian hapus cabang lama, salin cabang baru di tempatnya dan mulai lagi dari sana.

git branch -D oldbranch
git checkout -b oldbranch newbranch

Jika sudah disiarkan, maka hapus cabang lama dari semua repositori, dorong cabang redone ke paling tengah, dan tarik kembali ke bawah ke semua.

ppostma1
sumber
4
Peringatan tentang siaran harus benar-benar lebih eksplisit tentang betapa mengerikannya ide ini. Ini akan merusak versi semua orang dari cabang itu dan hanya sangat berguna jika Anda bekerja dengan repositori jarak jauh (github / bitbucket) yang hanya dapat Anda akses.
RobbyD
Tidak seburuk mendorong file konfigurasi yang dimodifikasi ke aliran produksi. Itu tidak akan korup, itu hanya rebranch dari komit sebelumnya, jadi ini cara untuk memindahkan pointer cabang ke versi sebelumnya. Mudah-mudahan itu hanya berdampak pada repositori lokal
ppostma1
5

Jika Anda ingin mengembalikan mergekomit, inilah yang harus Anda lakukan.

  1. Pertama, periksa git loguntuk menemukan id komit gabungan Anda. Anda juga akan menemukan beberapa id induk yang terkait dengan penggabungan (lihat gambar di bawah).

masukkan deskripsi gambar di sini

Catat id gabungan yang ditunjukkan dengan warna kuning. ID induk adalah yang ditulis pada baris berikutnya sebagai Merge: parent1 parent2. Sekarang...

Cerita pendek:

  1. Beralih ke cabang tempat penggabungan dilakukan. Kemudian Lakukan saja git revert <merge commit id> -m 1yang akan membuka vikonsol untuk memasukkan pesan komit. Tulis, simpan, keluar, selesai!

Cerita panjang:

  1. Beralih ke cabang tempat penggabungan dilakukan. Dalam kasus saya, itu adalah testcabang dan saya mencoba untuk menghapus feature/analytics-v3cabang dari itu.

  2. git revertadalah perintah yang mengembalikan komit apa pun. Tetapi ada trik jahat ketika mengembalikan mergekomit. Anda harus memasukkan -mbendera jika tidak maka akan gagal. Mulai sekarang, Anda perlu memutuskan apakah Anda ingin mengembalikan cabang Anda dan membuatnya terlihat persis seperti pada parent1atau parent2melalui:

git revert <merge commit id> -m 1(kembali ke parent2)

git revert <merge commit id> -m 2(kembali ke parent1)

Anda dapat login orang tua ini untuk mencari tahu ke mana Anda ingin pergi dan itu adalah akar dari semua kebingungan.

saran3h
sumber
5

Semua jawaban sudah mencakup sebagian besar hal tetapi saya akan menambahkan 5 sen saya. Singkatnya, mengembalikan komit gabungan cukup sederhana:

git revert -m 1 <commit-hash>

Jika Anda memiliki izin, Anda dapat mendorongnya langsung ke cabang "master" jika tidak, cukup dorong ke cabang "kembalikan" dan buat permintaan tarik.

Anda mungkin menemukan info lebih berguna tentang subjek ini di sini: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html

xproph
sumber
1

Saya menemukan membuat tambalan terbalik antara dua titik akhir yang diketahui dan menerapkan tambalan itu akan berhasil. Ini menganggap bahwa Anda telah membuat snapshot (tag) dari cabang master Anda atau bahkan cadangan dari cabang master Anda mengatakan master_bk_01012017.

Katakanlah cabang kode yang Anda gabungkan menjadi master adalah mycodebranch.

  1. Master checkout
  2. Buat tambalan terbalik biner penuh antara master dan cadangan Anda. git diff --binary master..master_bk_01012017 > ~/myrevert.patch
  3. Periksa tambalan Anda git apply --check myrevert.patch
  4. Terapkan tambalan dengan sign-off git am --signoff < myrevert.patch
  5. Jika Anda perlu memasukkan kode ini lagi setelah diperbaiki, Anda harus bercabang dari master yang dikembalikan dan checkout cabang perbaikan git branch mycodebranch_fix git checkout mycodebranch_fix
  6. Di sini Anda perlu menemukan kunci SHA untuk mengembalikan dan mengembalikan kembali git revert [SHA]
  7. Sekarang Anda dapat menggunakan mycodebranch_fix untuk memperbaiki masalah, komit, dan bergabung kembali ke master setelah selesai.
alexplain
sumber
1

Jawaban yang ditandai dengan benar bekerja untuk saya, tetapi saya harus meluangkan waktu untuk menentukan apa yang terjadi .. Jadi saya memutuskan untuk menambahkan jawaban dengan langkah mudah sederhana untuk kasus seperti milik saya ..

Katakanlah kita punya cabang A dan B .. Anda menggabungkan cabang A ke cabang B dan mendorong cabang B ke dirinya sendiri jadi sekarang penggabungan adalah bagian dari itu .. Tapi Anda ingin kembali ke komit terakhir sebelum penggabungan .. Apa yang harus dilakukan? kamu lakukan?

  1. Buka folder git root Anda (folder proyek biasanya) dan gunakan git log
  2. Anda akan melihat riwayat komit terbaru - komit memiliki properti komit / penulis / tanggal sementara penggabungan juga memiliki properti gabungan - sehingga Anda melihatnya seperti ini:

    commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>

  3. Gunakan git log <parentHashA>dan git log <parentHashB>- Anda akan melihat riwayat komit dari cabang induk tersebut - komit pertama dalam daftar adalah yang terbaru

  4. Ambil <commitHash>komit yang Anda inginkan, buka folder git root Anda dan gunakan git checkout -b <newBranchName> <commitHash>- yang akan membuat cabang baru mulai dari komit terakhir yang Anda pilih sebelum penggabungan .. Voila, siap!
Божидар Йовчев
sumber
0

Saya juga menghadapi masalah ini pada PR yang telah digabung ke cabang utama dari repo GitHub.

Karena saya hanya ingin memodifikasi beberapa file diubah tetapi tidak seluruh perubahan PR membawa, saya harus amendyang merge commitdengan git commit --am.

Langkah:

  1. Pergi ke cabang yang ingin Anda ubah / kembalikan beberapa file yang dimodifikasi
  2. Lakukan perubahan yang Anda inginkan sesuai dengan file yang dimodifikasi
  3. jalankan git add *ataugit add <file>
  4. jalankan git commit --amdan validasikan
  5. Lari git push -f

Mengapa ini menarik:

  • Itu membuat pengarang PR tetap tidak berubah
  • Itu tidak mematahkan pohon git
  • Anda akan ditandai sebagai committer (menggabungkan komit pembuat akan tetap tidak berubah)
  • Git bertindak seolah-olah Anda menyelesaikan konflik, itu akan menghapus / mengubah kode dalam file yang dimodifikasi seolah-olah Anda secara manual memberitahu GitHub untuk tidak menggabungkannya apa adanya.
Maxime Lafarie
sumber
0

Saya menemukan penjelasan yang bagus untuk Cara Mengembalikan Penggabungan dari tautan ini dan saya menyalin rekatkan penjelasan di bawah ini dan akan sangat membantu kalau-kalau tautan di bawah tidak berfungsi.

Cara mengembalikan gabungan yang salah Alan ([email protected]) berkata:

Saya memiliki cabang utama. Kami memiliki cabang dari beberapa pengembang yang sedang mengerjakan. Mereka mengklaim siap. Kami menggabungkannya ke cabang master. Itu merusak sesuatu sehingga kami mengembalikan penggabungan. Mereka membuat perubahan pada kode. mereka sampai pada titik di mana mereka mengatakan itu ok dan kita bergabung lagi. Ketika diperiksa, kami menemukan bahwa perubahan kode yang dibuat sebelum pengembalian tidak di cabang master, tetapi perubahan kode setelah berada di cabang master. dan meminta bantuan untuk pulih dari situasi ini.

Sejarah segera setelah "kembalikan penggabungan" akan terlihat seperti ini:

---o---o---o---M---x---x---W
              /
      ---A---B

di mana A dan B berada di sisi pengembangan yang tidak begitu baik, M adalah gabungan yang membawa perubahan prematur ini ke garis utama, x adalah perubahan yang tidak terkait dengan apa yang cabang samping lakukan dan sudah dibuat pada garis utama, dan W adalah " kembali dari penggabungan M "(bukankah W terlihat terbalik?) TKI, "diff W ^ .. W" mirip dengan "diff -RM ^ .. M".

"Kembalikan" penggabungan dapat dilakukan dengan:

$ git revert -m 1 M Setelah pengembang cabang samping memperbaiki kesalahan mereka, sejarahnya mungkin terlihat seperti ini:

---o---o---o---M---x---x---W---x
              /
      ---A---B-------------------C---D

di mana C dan D akan memperbaiki apa yang rusak di A dan B, dan Anda mungkin sudah memiliki beberapa perubahan lain pada garis utama setelah W.

Jika Anda menggabungkan cabang samping yang diperbarui (dengan D di ujungnya), tidak ada perubahan yang dibuat dalam A atau B akan ada dalam hasilnya, karena mereka dikembalikan oleh W. Itulah yang dilihat Alan.

Linus menjelaskan situasinya:

Mengembalikan komit reguler hanya secara efektif membatalkan apa yang komit lakukan, dan cukup mudah. Namun, mengembalikan komit gabungan juga membatalkan data yang diubah komit tersebut, tetapi itu sama sekali tidak berdampak pada sejarah yang dimiliki oleh gabungan tersebut. Jadi penggabungan akan tetap ada, dan itu masih akan dilihat sebagai menggabungkan dua cabang bersama, dan penggabungan di masa depan akan melihat penggabungan tersebut sebagai keadaan bersama terakhir - dan pengembalian yang mengembalikan gabungan yang dibawa tidak akan memengaruhi sama sekali. Jadi "kembalikan" membatalkan perubahan data, tetapi sangat tidak"undo" dalam arti bahwa itu tidak membatalkan efek komit pada sejarah repositori. Jadi, jika Anda berpikir tentang "kembalikan" sebagai "kembalikan", maka Anda akan selalu kehilangan bagian ini dari kembalinya. Ya, itu membatalkan data, tetapi tidak, itu tidak membatalkan sejarah. Dalam situasi seperti itu, Anda ingin mengembalikan yang sebelumnya, yang akan membuat sejarah terlihat seperti ini:

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

di mana Y adalah revert dari W. "Revert of the revert" dapat dilakukan dengan:

$ git revert W Riwayat ini akan (mengabaikan kemungkinan konflik antara apa yang diubah W dan W..Y) setara dengan tidak memiliki W atau Y sama sekali dalam sejarah:

---o---o---o---M---x---x-------x----
              /
      ---A---B-------------------C---D

dan menggabungkan cabang samping lagi tidak akan memiliki konflik yang timbul dari pengembalian sebelumnya dan pengembalian kembali.

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

Tentu saja perubahan yang dibuat dalam C dan D masih dapat bertentangan dengan apa yang dilakukan oleh salah satu dari x, tetapi itu hanya konflik gabungan normal.

MK446
sumber
-2

Seperti yang disebutkan Ryan, git revertbisa menyulitkan penggabungan jalan, jadi git revertmungkin bukan yang Anda inginkan. Saya menemukan bahwa menggunakan git reset --hard <commit-hash-prior-to-merge>perintah lebih bermanfaat di sini.

Setelah Anda melakukan bagian hard reset, Anda kemudian dapat memaksa mendorong ke cabang jauh, yaitu git push -f <remote-name> <remote-branch-name>, di mana <remote-name>sering disebut origin. Dari titik itu Anda dapat menggabungkan kembali jika mau.

Harry Wang
sumber
4
Apa pun yang melibatkan gaya dorong adalah ide yang buruk kecuali Anda adalah satu-satunya yang menggunakan repo, dan Anda tahu persis apa yang Anda lakukan. Mengembalikan dengan git revert dan kemudian mungkin mengembalikan revert dengan git revert (jika Anda perlu mengembalikan sesuatu) adalah alternatif yang jauh lebih aman.
oyvind