Membatalkan git rebase

3180

Bagaimana saya bisa dengan mudah membatalkan git rebase?

Ide saya saat ini hanya pendekatan manual:

  1. git checkout pada orang tua komit untuk kedua cabang
  2. Buat cabang temp dari sana
  3. git cherry-pick semua dilakukan dengan tangan
  4. ganti cabang tempat saya rebased oleh cabang yang dibuat secara manual

Dalam situasi saya saat ini, ini akan berhasil karena saya dapat dengan mudah melihat komit dari kedua cabang (satu adalah barang saya, yang lain adalah barang rekan saya).

Namun pendekatan saya menganggap saya sebagai suboptimal dan rawan kesalahan (misalkan saya baru saja rebased dengan 2 cabang saya sendiri).

Klarifikasi : Saya sedang berbicara tentang rebase di mana sekelompok komit diputar ulang. Bukan hanya satu.

webmat
sumber
6
JUGA perhatikan bahwa selama rebase Anda dapat mengecualikan komit, atau menghancurkannya; perubahan ini tidak dapat dikembalikan tanpa penunjuk ke node asli atau memilah-milah reflog, sehingga cherrypicking tidak akan berfungsi.
ANeves

Jawaban:

4337

Cara termudah adalah dengan menemukan komit dari cabang seperti itu segera sebelum rebase dimulai di reflog ...

git reflog

dan untuk mereset cabang saat ini (dengan peringatan yang biasa tentang menjadi benar-benar yakin sebelum mengatur ulang dengan --hardopsi).

Misalkan komit lama ada HEAD@{5}di ref log:

git reset --hard HEAD@{5}

Di Windows, Anda mungkin perlu mengutip referensi:

git reset --hard "HEAD@{5}"

Anda dapat memeriksa riwayat kandidat kepala lama dengan hanya melakukan git log HEAD@{5}( Windows git log "HEAD@{5}" :).

Jika Anda tidak menonaktifkan per reflog cabang, Anda seharusnya bisa melakukannya git reflog branchname@{1}karena rebase melepaskan kepala cabang sebelum menempel kembali ke kepala akhir. Saya akan mengecek ini, meskipun karena saya belum memverifikasi ini baru-baru ini.

Per default, semua reflog diaktifkan untuk repositori non-telanjang:

[core]
    logAllRefUpdates = true
CB Bailey
sumber
115
Git reflog memang luar biasa, ingatlah Anda bisa mendapatkan hasil keluaran yang diformat dengan lebih baik git log -g(tip dari Scott Chacon's progit.org/book ).
karmi
60
@Zach: git rebase --abort( -itidak masuk akal dengan --abort) adalah untuk meninggalkan rebase yang belum selesai - baik karena ada konflik atau karena itu interaktif atau keduanya; ini bukan tentang membatalkan rebase yang berhasil yang merupakan pertanyaannya. Anda akan menggunakan rebase --abortatau reset --hardbergantung pada situasi di mana Anda berada. Anda seharusnya tidak perlu melakukan keduanya.
CB Bailey
311
Hanya dalam kasus, membuat cadangan pertama: git tag BACKUP. Anda dapat kembali ke sana jika terjadi kesalahan:git reset --hard BACKUP
kolypto
6
Jika Anda telah membuat banyak komit HEAD @ {#} Anda cari akan diawali dengan commit:sebagai lawan rebase:. Kedengarannya jelas tetapi sedikit membingungkan saya.
Warpling
4
Bergabung dengan pesta setelah rebase yang tidak disengaja: D. Bukankah akan git reset --hard ORIG_HEADmelakukan trik juga segera setelah rebase yang tidak disengaja?
quaylar
1488

Sebenarnya, rebase menyimpan titik awal Anda ORIG_HEADjadi ini biasanya sesederhana:

git reset --hard ORIG_HEAD

Namun, the reset, rebasedan mergesemua menyimpan HEADpointer asli Anda ke dalam ORIG_HEADjadi, jika Anda telah melakukan salah satu dari perintah itu sejak rebase Anda mencoba untuk membatalkan maka Anda harus menggunakan reflog.

Pat Notz
sumber
34
Dalam hal ORIG_HEADtidak lagi berguna, Anda juga dapat menggunakan branchName@{n}sintaksis, di mana nposisi ke-n sebelumnya dari penunjuk cabang. Jadi misalnya, jika Anda rebase featureAcabang ke cabang Anda master, tetapi Anda tidak menyukai hasil rebase, maka Anda bisa melakukannya git reset --hard featureA@{1}untuk mengatur ulang cabang kembali ke tempat itu sebelum Anda melakukan rebase. Anda dapat membaca lebih lanjut tentang sintaks cabang @ {n} di dokumentasi Git resmi untuk revisi .
15
Ini yang paling mudah. Tindak lanjuti dengan itu git rebase --abort.
Seph
1
@DaBlick, ini bekerja dengan baik untuk saya setelah rebase yang sukses tanpa konflik git 2.17.0.
dvlsg
4
Dan biarkan saya melengkapinya: git reset --hard ORIG_HEADbisa digunakan berulang-ulang untuk memutar kembali dan lagi. Katakan, Jika A --- rebase ke --- B --- rebase ke --- C, sekarang saya di C, saya bisa kembali ke A dengan menggunakan dua kaligit reset --hard ORIG_HEAD
CalvinChe
5
@Seph Bisakah Anda menjelaskan mengapa Anda menyarankan untuk menindaklanjuti git rebase --abort?
UpTheCreek
386

Jawaban Charles berhasil, tetapi Anda mungkin ingin melakukan ini:

git rebase --abort

untuk membersihkan setelah reset.

Kalau tidak, Anda mungkin mendapatkan pesan " Interactive rebase already started".

Allan
sumber
4
Yang ini menghapus bagian "| REBASE" di prompt saya. +1
Wouter Thielen
62
Bukan itu pertanyaannya. Pertanyaannya adalah bagaimana cara membatalkan rebase yang sudah selesai.
Arunav Sanyal
2
Seharusnya komentar tentang jawaban Charles, karena tidak menjawab pertanyaan pada tanggal
Murmel
Hm, saya tidak harus melakukan itu.
Viktor Seč
1
Satu-satunya yang bekerja untuk saya!
Alexandre Picard
90

Menyetel ulang cabang ke objek komit yang menjuntai dari tip lamanya tentu saja merupakan solusi terbaik, karena mengembalikan keadaan sebelumnya tanpa mengeluarkan usaha apa pun. Tetapi jika Anda kehilangan komitmen tersebut (mis. Karena Anda mengumpulkan sampah di repositori Anda untuk sementara waktu, atau ini adalah klon baru), Anda selalu dapat rebase cabang lagi. Kunci untuk ini adalah --ontosaklar.

Katakanlah Anda memiliki cabang topik yang secara imajinatif dipanggil topic, yang Anda cabut masterketika ujungnya masteradalah 0deadbeefkomit. Pada titik tertentu saat di topiccabang, Anda melakukannya git rebase master. Sekarang Anda ingin membatalkan ini. Begini caranya:

git rebase --onto 0deadbeef master topic

Ini akan mengambil semua komitmen topicyang tidak aktif masterdan mengulanginya di atas 0deadbeef.

Dengan --onto, Anda dapat mengatur ulang sejarah Anda menjadi hampir semua bentuk apa pun .

Selamat bersenang-senang. :-)

Aristoteles Pagaltzis
sumber
3
Saya pikir ini adalah pilihan terbaik karena fleksibilitasnya. Saya bercabang b1 dari master, lalu rebed b1 menjadi cabang b2 baru, kemudian ingin mengembalikan b1 untuk didasarkan pada master lagi. Saya suka git - terima kasih!
ripper234
2
Ini pilihan terbaik di sini! Itu menyimpan semua perubahan yang saya miliki di cabang saya saat ini, dan menghapus semua yang tidak diinginkan!
Alicia Tang
Saya akan mengatakan itu dengan kombinasi --ontodan -iAnda dapat mengatur ulang sejarah Anda menjadi hampir semua bentuk apa pun. Gunakan gitk (atau gitx di mac) untuk melihat bentuk yang Anda buat :-).
rjmunro
69

Saya benar-benar meletakkan tag cadangan pada cabang sebelum saya melakukan operasi nontrivial (kebanyakan rebases adalah sepele, tapi saya akan melakukannya jika terlihat rumit di mana saja).

Kemudian, mengembalikannya semudah git reset --hard BACKUP.

Alex Gontmakher
sumber
2
Saya juga melakukan ini. Ini juga berguna untuk mendapatkan BACKUP berbeda .. KEPALA untuk memastikan Anda mengubah apa yang Anda maksudkan.
Paul Bone
5
Saya dulu juga melakukan itu, tetapi karena saya merasa lebih nyaman dengan reflog saya tidak lagi merasa perlu. Reflog pada dasarnya melakukan ini atas nama Anda setiap kali Anda mengganti HEAD.
Pete Hodgson
4
Yah, saya lebih suka nama yang bermakna, karena mencari item yang tepat di reflog terkadang tidak menyenangkan sama sekali.
Alex Gontmakher
12
Anda sebenarnya bahkan tidak perlu membuat cabang cadangan, Anda cukup menggunakan branchName@{n}sintaksis, di sini nadalah posisi ke-n dari penunjuk cabang. Jadi misalnya, jika Anda rebase featureAcabang ke cabang Anda master, tetapi Anda tidak menyukai hasil rebase, maka Anda bisa melakukannya git reset --hard featureA@{1}untuk mengatur ulang cabang kembali ke tempat itu sebelum Anda melakukan rebase. Anda dapat membaca lebih lanjut tentang branch@{n}sintaks di dokumen resmi Git untuk revisi .
2
Sebenarnya, Anda bahkan tidak perlu menggunakan sintaksis di atas, menurut jawaban Pat Notz , yang asli HEADdari cabang disimpan sementara ORIG_HEAD. Tetapi teknik menggunakan label cabang cadangan juga berfungsi, itu hanya langkah-langkah lebih lanjut.
68

Jika Anda telah mendorong cabang Anda ke repositori jarak jauh (biasanya asalnya) dan kemudian Anda telah melakukan rebase sukses (tanpa penggabungan) ( git rebase --abortmemberikan "Tidak ada rebase sedang berlangsung") Anda dapat dengan mudah mengatur ulang cabang menggunakan perintah:

git reset --hard origin / {branchName}

Contoh:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean
Maksym
sumber
Itu jawaban yang tepat untuk saya. Rebase dan komit sebelum rebase memiliki ID komit yang sama, dan kembali ke HEAD {1} tidak akan mengembalikan rebase!
Bill Kotsias
23

Menggunakan reflogtidak berhasil untuk saya.

Apa yang berhasil bagi saya mirip dengan yang dijelaskan di sini . Buka file dalam .git / logs / ref yang diberi nama setelah cabang yang telah direbase dan temukan baris yang berisi "rebase finsihed", sesuatu seperti:

5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Periksa komit kedua yang terdaftar di telepon.

git checkout 88552c8f

Setelah dikonfirmasi ini berisi perubahan saya yang hilang, saya bercabang dan menghela napas lega.

git log
git checkout -b lost_changes
Keris
sumber
3
Whoa - dari tautan itu, "Ada satu peringatan: Saya kehilangan sejarah cabang tetapi dalam kasus ini tidak terlalu penting. Saya hanya senang telah mengambil perubahan saya." ?
ruffin
16

Untuk banyak komit, ingat bahwa komit apa pun merujuk semua riwayat yang mengarah pada komit itu. Jadi dalam jawaban Charles, bacalah "komitmen lama" sebagai "komitmen terbaru". Jika Anda mengatur ulang ke komit itu, maka semua riwayat yang mengarah ke komit itu akan muncul kembali. Ini harus melakukan apa yang Anda inginkan.

Greg Hewgill
sumber
11

Mengikuti solusi dari @Allan dan @Zearin, saya berharap saya bisa melakukan komentar saja tetapi saya tidak memiliki reputasi yang cukup, jadi saya telah menggunakan perintah berikut:

Alih-alih melakukan git rebase -i --abort (perhatikan i ) saya harus hanya melakukan git rebase --abort( tanpa yang -i ).

Menggunakan keduanya -idan--abort pada saat yang sama menyebabkan Git menunjukkan kepada saya daftar penggunaan / opsi.

Jadi status cabang saya sebelumnya dan saat ini dengan solusi ini adalah:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$
Matheus Felipe
sumber
11

Jika Anda berhasil rebased terhadap cabang jarak jauh dan tidak bisa git rebase --abortAnda masih bisa melakukan beberapa trik untuk menyelamatkan pekerjaan Anda dan tidak memiliki dorongan paksa. Misalkan cabang Anda saat ini yang diubah oleh kesalahan dipanggil your-branchdan sedang dilacakorigin/your-branch

  • git branch -m your-branch-rebased # ubah nama cabang saat ini
  • git checkout origin/your-branch # checkout ke status terbaru yang diketahui asalnya
  • git checkout -b your-branch
  • periksa git log your-branch-rebased, bandingkan git log your-branchdan tentukan komit yang hilang dariyour-branch
  • git cherry-pick COMMIT_HASH untuk setiap komit di your-branch-rebased
  • dorong perubahan Anda. Harap perhatikan bahwa ada dua cabang lokal yang terkait remote/your-branchdan Anda hanya perlu mendorongyour-branch
Sergey P. alias biru
sumber
4

Katakanlah saya rebase master ke cabang fitur saya dan saya mendapatkan 30 commit baru yang merusak sesuatu. Saya telah menemukan bahwa sering kali paling mudah menghilangkan komitmen buruk.

git rebase -i HEAD~31

Rebase interaktif untuk 31 komit terakhir (tidak ada salahnya jika Anda mengambil terlalu banyak).

Cukup ambil komit yang ingin Anda singkirkan dan tandai dengan "d", bukan "pick". Sekarang komit dihapus secara efektif membatalkan rebase (jika Anda menghapus hanya komit yang baru saja Anda dapatkan saat rebasing).

Hardev
sumber
3

Untuk pemula / siapa pun yang terlalu takut melakukan hard reset, Anda dapat checkout komit dari reflog, dan kemudian menyimpannya sebagai cabang baru.

git reflog

Temukan komit tepat sebelum Anda mulai rebasing. Anda mungkin perlu menggulir lebih jauh ke bawah untuk menemukannya (tekan Enter atau PageDown). Perhatikan nomor KEPALA dan ganti 57:

git checkout HEAD@{57}

Tinjau cabang / komit, jika terlihat bagus buat cabang baru menggunakan KEPALA ini:

git checkout -b new_branch_name
Andrew
sumber
2

Jika Anda menggunakan cabang, Anda dapat menggunakan:

git reset --hard @{1}

Tidak hanya ada log referensi untuk HEAD (diperoleh oleh git reflog), ada juga reflog untuk setiap cabang (diperoleh oleh git reflog <branch>). Jadi, jika Anda aktif mastermaka git reflog masterakan mendaftar semua perubahan ke cabang itu. Anda dapat merujuk ke perubahan oleh master@{1}, master@{2}, dll

git rebase biasanya akan mengubah KEPALA beberapa kali tetapi cabang saat ini akan diperbarui hanya sekali.

@{1}hanyalah jalan pintas untuk cabang saat ini , jadi itu sama dengan master@{1}jika Anda aktifmaster .

git reset --hard ORIG_HEADtidak akan berfungsi jika Anda digunakan git resetselama interaktif rebase.

devconsole
sumber
1

Apa yang biasanya saya lakukan adalah git reset #commit_hash

untuk komit terakhir di mana saya pikir rebase tidak berpengaruh.

kemudian git pull

Sekarang cabang Anda harus sama persis seperti master dan rebased commit seharusnya tidak ada di dalamnya.

Sekarang kita bisa memilih komit di cabang ini.

mrigendra
sumber
1

Saya mencoba semua saran dengan reset dan reflog tanpa hasil. Mengembalikan sejarah lokal IntelliJ menyelesaikan masalah file yang hilang

pengguna3638751
sumber
Terima kasih! Tidak pernah menggunakan riwayat lokal sebelumnya, tetapi ini ternyata menjadi pilihan termudah bagi saya untuk memulihkan beberapa kode yang direbahkan secara tidak sengaja. Fitur yang sangat bagus tapi agak tersembunyi.
Magnus W
0

git reset --hard origin / {branchName}

adalah solusi yang tepat untuk mengatur ulang semua perubahan lokal Anda yang dilakukan dengan rebase.

Damodar P
sumber
1
jika Anda sulit mengatur ulang origin/branchAnda mungkin kehilangan perubahan antara HEAD dan titik itu. Anda tidak ingin itu secara umum.
bluesmonk
Inilah yang saya inginkan dalam kasus saya. Jadi upvoting.
Mandar Vaze
-4

Jika Anda mengacaukan sesuatu dalam git rebase, misalnya git rebase --abort, saat Anda memiliki file yang tidak dikomit, mereka akan hilang dan git reflogtidak akan membantu. Ini terjadi pada saya dan Anda harus berpikir di luar kotak di sini. Jika Anda beruntung seperti saya dan menggunakan IntelliJ Webstorm maka Anda dapat right-click->local historydan dapat kembali ke keadaan file / folder sebelumnya, apa pun kesalahan yang Anda lakukan dengan perangkat lunak versi. Itu selalu baik untuk menjalankan kegagalan yang lain.

stevek
sumber
5
git rebase --abortbatalkan rebase aktif, itu tidak membatalkan rebase. Juga, menggunakan dua VCS pada saat yang sama adalah ide yang buruk. Ini adalah fitur yang bagus dalam perangkat lunak Jetbrains tetapi Anda sebaiknya tidak menggunakan keduanya. Lebih baik mempelajari Git, terutama saat menjawab pertanyaan tentang Stack Overflow yang membahas tentang Git.
dudewad