Memotong komit gabungan Git

183

Ambil contoh berikut:

Saya memiliki beberapa pekerjaan di cabang topik dan sekarang saya siap untuk bergabung kembali ke master:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1

Saya melakukan penggabungan dari master, menyelesaikan konflik dan sekarang saya memiliki:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | eb3b733 3                     [origin/master]
|/  
* 38abeae 1

Sekarang, penggabungan ini memakan waktu lama, jadi saya melakukan pengambilan lagi dan perhatikan bahwa cabang master jarak jauh memiliki perubahan baru:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
| | * e7affba 4                   [origin/master]
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Jika saya mencoba 'git rebase origin / master' dari master, saya terpaksa menyelesaikan semua konflik lagi, dan saya juga kehilangan komit gabungan:

* d4de423 2       [master]
* e7affba 4       [origin/master]
* eb3b733 3
| * b62cae6 2     [topic]
|/  
* 38abeae 1

Apakah ada cara bersih untuk memulai kembali komit gabungan jadi saya berakhir dengan sejarah seperti yang saya tunjukkan di bawah ini?

*   51984c7 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | e7affba 4                     [origin/master]
* | eb3b733 3
|/  
* 38abeae 1
jipumarino
sumber
74
TL; DR:git rebase --preserve-merges origin/master
Ilia K.
6
Sehubungan dengan keharusan menyelesaikan kembali konflik, Anda mungkin ingin melihat git rerere .
Parker Coates
git config --global pull.rebase preserve untuk selalu menjaga komitmen gabungan selama rebase
galath
4
Peringatan: dimulai dengan Git 2.18 (Q2 2018, 5 tahun kemudian), git --rebase-mergespada akhirnya akan menggantikan yang lama git --preserve-merges. Lihat Apa sebenarnya yang dilakukan Git " rebase --preserve-merges(dan mengapa?)
VonC
1
--preserve-mergessudah ditinggalkan. Gunakangit rebase --rebase-merges origin/master
Arjun Sreedharan

Jawaban:

126

Ada dua opsi di sini.

Pertama adalah melakukan rebase interaktif dan mengedit komit penggabungan, mengulang penggabungan secara manual dan melanjutkan rebase.

Cara lain adalah dengan menggunakan --rebase-mergesopsi aktif git rebase, yang dijelaskan sebagai berikut dari manual: "Secara default, rebase hanya akan menjatuhkan komit gabungan dari daftar todo, dan menempatkan komit rebased ke cabang tunggal linier. Dengan --rebase- penggabungan, rebase sebagai gantinya akan mencoba untuk melestarikan struktur percabangan di dalam komit yang akan direbase, dengan menciptakan kembali komit penggabungan. Setiap konflik penggabungan yang diselesaikan atau amandemen manual dalam komit gabungan ini harus diselesaikan / diterapkan kembali secara manual. "

siride
sumber
16
Saya mencoba opsi -p, dan itu memang meninggalkan sejarah komit seperti yang saya inginkan, tetapi memaksa saya untuk menyelesaikan konflik lagi, bahkan dalam file yang tidak diedit dalam asal / master. Pada saran pertama Anda, manakah urutan perintah yang tepat?
jipumarino
2
@ jipumarino: git rebase -i (katakan itu untuk mengedit komit gabungan), ketika sampai ke komit gabungan, atur ulang git --hard HEAD ^, git menggabungkan, memperbaiki konflik, perintah git, git rebase - lanjutkan. Anda mungkin juga ingin melihat git rerere yang seharusnya membantu hal semacam ini (tapi saya tidak pernah menggunakannya, jadi saya tidak bisa menawarkan saran atau bantuan).
siride
2
Terima kasih. Saya mengaktifkan rerere dan mencoba dengan rebase -p dan berfungsi sebagaimana mestinya.
jipumarino
3
Berikut ini adalah posting blog yang sangat bagus menggambarkan situasi yang tepat ini: Rebasing Menggabungkan Komit di Git
kynan
1
rere bukanlah solusi, karena Anda masih harus menyelesaikan penggabungan secara manual saat pertama kali melintas.
Flimm
29

Oke, itu pertanyaan lama dan sudah menerima jawaban @siride, tetapi jawaban itu tidak cukup untuk saya, karena --preserve-mergesmemaksa Anda menyelesaikan semua konflik untuk kedua kalinya. Solusi saya berdasarkan ide dengan @Tobi Btetapi dengan perintah langkah demi langkah yang tepat

Jadi kita akan mulai pada keadaan seperti itu berdasarkan contoh dalam pertanyaan:

*   8101fe3 Merge branch 'topic'  [HEAD -> master]
|\  
| * b62cae6 2                     [topic]
| |
| | * f5a7ca8 5                   [origin/master]
| | * e7affba 4
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Perhatikan bahwa kita memiliki 2 komit di depan, jadi cherry-pick tidak akan berfungsi.

  1. Pertama-tama, mari kita buat riwayat yang benar yang kita inginkan:

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    Kami gunakan --preserve-mergesuntuk menyimpan komit gabungan kami dalam sejarah. Kami gunakan --strategy=oursuntuk mengabaikan semua konflik penggabungan karena kami tidak peduli tentang konten apa yang akan ada dalam komit gabungan, kami hanya perlu riwayat yang bagus sekarang.

    Sejarah akan terlihat seperti itu (mengabaikan master):

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. Ayo dapatkan indeks yang benar sekarang.

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    

    Kami mungkin mendapatkan beberapa konflik penggabungan tambahan di sini, tetapi itu hanya akan menjadi konflik dari file yang diubah antara 8101fe3dan f5a7ca8, tetapi tidak termasuk konflik yang sudah diselesaikan daritopic

    Sejarah akan terlihat seperti ini (mengabaikan riwayat yang benar):

    *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
    |\  
    * | f5a7ca8 5                   [origin/master]
    * | e7affba 4
    | *   8101fe3 Merge branch 'topic'
    | |\  
    | | * b62cae6 2                     [topic]
    |/ /
    * / eb3b733 3
    |/  
    * 38abeae 1
    
  3. Tahap terakhir adalah menggabungkan cabang kami dengan riwayat yang benar dan cabang dengan indeks yang benar

    git reset --soft correct-history
    git commit --amend
    

    Kami menggunakan reset --softuntuk mengatur ulang cabang kami (dan sejarah) untuk mengoreksi-sejarah, tetapi biarkan indeks dan pohon yang bekerja apa adanya. Lalu kami gunakan commit --amenduntuk menulis ulang komit gabungan kami, yang dulu memiliki indeks salah, dengan indeks baik kami dari master.

    Pada akhirnya kita akan memiliki status seperti itu (perhatikan id lain dari komit atas):

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
Ivan Naydonov
sumber
Ini luar biasa dan banyak membantu! Tapi saya tidak mendapatkan trik dengan commit --amend: dapatkah Anda menambahkan lebih banyak info tentang itu? Apa yang sebenarnya terjadi setelah Anda menjalankannya - Saya perhatikan SHA dari komit diubah - tetapi mengapa? Atau apa yang terjadi jika Anda tidak menjalankan ini?
ZenJ
1
@ ZenJ git commit --amendmenambahkan perubahan ke komit terakhir (HEAD, dalam hal ini komit gabungan). Karena konten komit berubah, hash diperbarui.
Dries Staelens
1
Untuk orang-orang yang tidak mengaktifkan 'rerere' diaktifkan sebelum memperbaiki konflik, solusi ini sangat bagus karena ini menyelamatkan Anda dari keharusan memperbaiki konflik lagi. Terima kasih!
Shackleford
6

Mengingat bahwa saya baru saja kehilangan satu hari mencoba mencari tahu ini dan benar-benar menemukan solusi dengan bantuan rekan kerja, saya pikir saya harus berpadu.

Kami memiliki basis kode yang besar dan kami harus berurusan dengan 2 cabang yang sedang dimodifikasi secara bersamaan. Ada cabang utama dan cabang sekunder jika Anda mau.

Sementara saya menggabungkan cabang sekunder ke cabang utama, pekerjaan berlanjut di cabang utama dan pada saat saya selesai, saya tidak dapat mendorong perubahan saya karena mereka tidak kompatibel.

Karena itu saya perlu "rebase" "gabungan" saya.

Beginilah akhirnya kami melakukannya:

1) membuat catatan SHA. mis .: c4a924d458ea0629c0d694f1b9e9576a3ecf506b

git log -1

2) Buat riwayat yang tepat tetapi ini akan memecah gabungan.

git rebase -s ours --preserve-merges origin/master

3) membuat catatan SHA. mis .: 29dd8101d78

git log -1

4) Sekarang reset ke tempat Anda sebelumnya

git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard

5) Sekarang gabungkan master saat ini ke cabang kerja Anda

git merge origin/master
git mergetool
git commit -m"correct files

6) Sekarang Anda memiliki file yang tepat, tetapi riwayat yang salah, dapatkan riwayat yang tepat di atas perubahan Anda dengan:

git reset 29dd8101d78 --soft

7) Dan kemudian - ubah hasil di komit gabungan asli Anda

git commit --amend

Voila!

Claude Peloquin
sumber
1

Sepertinya yang ingin Anda lakukan adalah menghapus gabungan pertama Anda. Anda dapat mengikuti prosedur berikut:

git checkout master      # Let's make sure we are on master branch
git reset --hard master~ # Let's get back to master before the merge
git pull                 # or git merge remote/master
git merge topic

Itu akan memberi Anda apa yang Anda inginkan.

Antoine Pelisse
sumber
4
Dengan diaktifkannya rerere, ini tampaknya memberikan hasil yang sama dengan solusi rebase -p yang diberikan di atas oleh siride.
jipumarino
0
  • Dari komit gabungan Anda
  • Cherry-pilih perubahan baru yang seharusnya mudah
  • salin barang-barang Anda
  • mengulang penggabungan dan menyelesaikan konflik hanya dengan menyalin file dari salinan lokal Anda;)
Tobi B
sumber
1
Jawaban ini terlihat bagus tetapi akan lebih berguna jika Anda memberikan perintah git yang sebenarnya, jika pengguna baru untuk git
Louise Davies