Bagaimana cara memindahkan commit tertentu berdasarkan pada cabang lain di git?

381

Situasi:

  • master ada di X
  • quickfix1 ada di X + 2 komit

Seperti yang:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Kemudian saya mulai bekerja pada quickfix2, tetapi secara tidak sengaja mengambil quickfix1 sebagai cabang sumber untuk menyalin, bukan master. Sekarang quickfix2 ada di X + 2 commit + 2 commit yang relevan.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Sekarang saya ingin memiliki cabang dengan quickfix2, tetapi tanpa 2 commit yang termasuk dalam quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Saya mencoba membuat tambalan dari revisi tertentu di quickfix2, tetapi tambalan tidak mempertahankan sejarah komit. Apakah ada cara untuk menyimpan histori komit saya, tetapi memiliki cabang tanpa perubahan di quickfix1?

Alex Yarmula
sumber
8
@Kevin Pertanyaan itu hanya menanyakan tentang memindahkan komit dari satu cabang ke cabang lainnya, yang ini memiliki persyaratan tambahan untuk tidak menyertakan komit quickfix1. (Perhatikan juga perbedaan jawaban.)
Scott Weldon

Jawaban:

372

Ini adalah kasus klasik dari rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Jadi kamu harus pergi

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

untuk:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Ini paling baik dilakukan pada pohon yang bersih.
Lihatgit config --global rebase.autostash true , terutama setelah Git 2.10 .

VONC
sumber
24
Berhati-hatilah bahwa langkah-langkah ini akan mengubah riwayat quickfix2, jadi jika Anda sudah berbagi cabang, gunakan memetik ceri sebagai gantinya (lihat jawaban berikut).
Max Chernyak
Hanya untuk catatan: dengan log SmartGit cukup seret q2ake Xdan pilih Rebase 2 komit dari opsi dialog yang terjadi.
Thomas S.
1
@ Thomas. Menarik. Itu adalah implementasi GUI yang bagus dari a git rebase --onto.
VonC
1
Saya harus akui, saya melakukan hal-hal konyol seperti melakukan ke cabang yang salah lebih sering dari yang seharusnya, tampilan log SmartGit GUI telah menyelamatkan saya berkali-kali dengan situasi yang sama.
WORMSS
1
@Cosine Setuju. Saya telah mengedit jawaban saya untuk menambahkan referensi ke rebase.autostashkonfigurasi: yang akan menghindari hilangnya pekerjaan yang sedang berjalan di pohon kerja saat melakukan rebase.
VonC
155

Anda dapat menggunakan git cherry-pickuntuk hanya memilih komit yang ingin Anda salin.

Mungkin cara terbaik adalah membuat cabang keluar dari master, kemudian dalam cabang itu gunakan git cherry-pickpada 2 commit dari quickfix2 yang Anda inginkan.

DJ.
sumber
Ini juga merupakan opsi terbaik jika Anda ingin memindahkan hanya satu komit. Terima kasih.
Alex
142

Hal paling sederhana yang dapat Anda lakukan adalah memilih cherry range. Itu melakukan hal yang sama seperti rebase --ontotetapi lebih mudah bagi mata :)

git cherry-pick quickfix1..quickfix2
Christoph
sumber
6
juga, tidak kehilangan komit asli, IIUC, jadi sepertinya lebih disukai untuk "play-it-safe" seperti saya;) atau apakah rebase --ontojuga mempertahankan perubahan asli?
aliasvel
6
keduanya rebasedan cherry-pickmemberi Anda kunci SHA baru. Itu karena setiap komit adalah snapshot unik dari repositori.
Christoph
6
Apa yang dimaksud @akavel adalah bahwa cherry-pick akan mempertahankan komitmen asli di cabang mereka yang benar
Mr_and_Mrs_D
4
Apa pun nilainya, saya mencoba cherry-pickkisaran seperti dalam jawaban ini dan itu membingungkan repo saya. Saya harus melakukan individu cherry-pickuntuk setiap komitmen. (Dan mungkin tidak usah dikatakan, tetapi jika ada orang yang berjuang, Anda harus cherry-pickmengikuti urutan kronologis bahwa komitmen Anda diterapkan.)
carmenism
3
git checkoutsangat penting di sini. apa KEPALA mu :)?
Sławomir Lenart
28

Saya percaya itu:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
sumber
3
cherry-pickbekerja dengan hash komit jadi, jika Anda hanya ingin mengambil komit dari suatu tempat dan meletakkannya di tempat lain ini adalah cara untuk pergi. Pastikan Anda melakukan checkout <branch>yang benar dari cabang pertama.
John Leidegren
-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Perintah lain yang lebih berguna di sini dengan penjelasan: Git Guide

Menggali
sumber