Sebagian memilih ceri komit dengan Git

501

Saya sedang mengerjakan 2 cabang berbeda: rilis dan pengembangan .

Saya perhatikan saya masih perlu mengintegrasikan beberapa perubahan yang dilakukan ke cabang rilis kembali ke cabang pengembangan .

Masalahnya adalah saya tidak perlu semua komit, hanya beberapa bakhil di file tertentu, jadi sederhana

git cherry-pick bc66559

tidak melakukan trik.

Ketika saya melakukan

git show bc66559

Saya dapat melihat diff tetapi tidak benar-benar tahu cara yang baik untuk menerapkan itu sebagian ke pohon kerja saya saat ini.

oliver
sumber

Jawaban:

792

Hal inti yang Anda inginkan di sini adalah git add -p( -padalah sinonim untuk --patch). Ini memberikan cara interaktif untuk memeriksa konten, memungkinkan Anda memutuskan apakah setiap bingkah harus masuk, dan bahkan membiarkan Anda mengedit tambalan secara manual jika perlu.

Untuk menggunakannya dalam kombinasi dengan cherry-pick:

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(Terima kasih kepada Tim Henigan untuk mengingatkan saya bahwa git-cherry-pick memiliki opsi --no-commit, dan terima kasih kepada Felix Rabe karena menunjukkan bahwa Anda perlu mengatur ulang! Jika Anda hanya ingin meninggalkan beberapa hal dari komit , Anda dapat menggunakan git reset <path>...untuk menghapus hanya file-file itu.)

Tentu saja Anda dapat memberikan jalur khusus add -pjika perlu. Jika Anda memulai dengan tambalan, Anda bisa mengganti cherry-pickdengan apply.


Jika Anda benar-benar menginginkan git cherry-pick -p <commit>(opsi itu tidak ada), Anda dapat menggunakannya

git checkout -p <commit>

Itu akan membedakan komit saat ini dengan komit yang Anda tentukan, dan memungkinkan Anda untuk menerapkan bakhil dari diff itu secara individual. Opsi ini mungkin lebih berguna jika komit yang Anda tarik memiliki konflik gabungan di bagian komit yang tidak Anda minati. (Namun, yang checkoutberbeda dari cherry-pick: checkoutmencoba menerapkan <commit>konten seluruhnya, cherry-pickmenerapkan perbedaan dari komit yang ditentukan dari orang tuanya. Ini berarti bahwa checkoutdapat menerapkan lebih dari sekedar komit itu, yang mungkin lebih dari yang Anda inginkan.)

Cascabel
sumber
Sebenarnya, jika saya mengikuti saran dengan git 1.7.5.4, 'git add -p' mengatakan 'Tidak ada perubahan' karena semuanya sudah ada dalam indeks. Saya perlu melakukan 'git reset HEAD' sebelum 'git add' - cara apa saja untuk menghindari reset itu dengan beberapa opsi?
Felix Rabe
@FelixRabe: Saya benar-benar terkejut bahwa pada beberapa titik cherry-pick -nternyata tidak membiarkan perubahan dipentaskan - konvensi pasti bahwa --no-commitopsi berhenti tepat sebelum komit, yaitu dengan semua perubahan dipentaskan. Saya akan menambahkan reset ke dalam jawabannya.
Cascabel
1
@Blixt Artinya, jika komit yang ada di cabang lain tetapi tidak cabang Anda saat ini ABCDEF, git checkout -p <F>tidak tidak hanya membuat Anda mendapatkan perubahan dari F, itu akan Anda ABCDEF semua tumbuk bersama-sama dan memungkinkan Anda memilah apa bagian dari yang Anda inginkan . Mengupas bahwa hanya beberapa perubahan dari F adalah menyakitkan. Di sisi lain, git cherry-pick -n <F>Anda hanya mendapatkan perubahan dari F - dan jika beberapa dari perubahan tersebut bertentangan, ini akan membantu Anda sehingga Anda dapat mengetahui cara menggabungkan dengan benar.
Cascabel
Saya punya masalah dengan ini ketika perubahan adalah penambahan file. The git resetakan menghapus dipentaskan file dan add -phanya akan mengatakan 'apa-apa untuk menambahkan'.
Ian Grainger
36

Dengan asumsi perubahan yang Anda inginkan ada di kepala cabang tempat Anda menginginkan perubahan itu, gunakan git checkout

untuk satu file:

git checkout branch_that_has_the_changes_you_want path/to/file.rb

untuk banyak file hanya daisy chain:

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb
Jay Swain
sumber
5
Itu menyalin seluruh file: tidak hanya perubahan.
Daftar Jeremy
1
Jawaban ini, sama seperti jawaban lain di sini sejauh ini, memiliki kelemahan besar: itu tidak mempertahankan penulis asli perubahan, alih-alih melakukan dengan nama Anda. Jika perubahan itu baik, Anda mencuri kredit seseorang, jika perubahan itu buruk, Anda menempatkan diri Anda di api. Sepertinya tidak ada jalan lain untuk memiliki git-pick -p, dan rasa malu itu masih belum ada.
pfalcon
15

Membangun Mike Monkiewicz jawaban Anda juga dapat menentukan satu atau lebih file untuk checkout dari sha1 / cabang yang disediakan.

git checkout -p bc66559 -- path/to/file.java 

Ini akan memungkinkan Anda untuk secara interaktif memilih perubahan yang ingin Anda terapkan ke versi file Anda saat ini.

Christian
sumber
5
Ini bermasalah jika versi file saat ini sangat berbeda dari versi itu. Anda akan diminta dengan berbagai perubahan yang tidak relevan (yang tidak muncul di komit). Juga, perubahan yang benar-benar Anda inginkan dapat muncul dalam "bentuk yang disamarkan" sebagai perbedaan dengan saat ini, bukan perbedaan asli. Mungkin saja perbedaan asli yang Anda inginkan konflik, dan harus digabung dengan benar; Anda tidak akan memiliki kesempatan itu di sini.
Kaz
1

Jika Anda ingin menentukan daftar file pada baris perintah, dan menyelesaikan semuanya dalam satu perintah atom, cobalah:

git apply --3way <(git show -- list-of-files)

--3way: Jika tambalan tidak berlaku bersih, Git akan membuat konflik gabungan sehingga Anda bisa menjalankan git mergetool. Menghilangkan --3wayakan membuat Git menyerah pada tambalan yang tidak berlaku bersih.

nyanpasu64
sumber
0

Jika "memetik sebagian ceri" berarti "di dalam file, memilih beberapa perubahan tetapi membuang yang lain", itu dapat dilakukan dengan memasukkan git stash:

  1. Apakah pick penuh ceri.
  2. git reset HEAD^ untuk mengubah seluruh komit yang dipetik cherry menjadi perubahan kerja yang tidak dipentaskan.
  3. Sekarang git stash save --patch: pilih bahan yang tidak diinginkan untuk disimpan secara interaktif.
  4. Git mengembalikan perubahan simpanan dari copy pekerjaan Anda.
  5. git commit
  6. Membuang tumpukan perubahan yang tidak diinginkan: git stash drop.

Kiat: jika Anda memberikan simpanan perubahan yang tidak diinginkan nama: git stash save --patch junkmaka jika Anda lupa melakukannya (6) sekarang, nanti Anda akan mengenali simpanan untuk apa itu.

Kaz
sumber
Jika Anda hanya memilih ceri, lalu mengatur ulang ... Anda tidak akan menyembunyikan apa pun. Seperti dikatakan di atas, Anda harus melakukan pick-ceri dengan --no-commit, atau reset --hard HEAD ~. Perhatikan bahwa Anda memproses secara negatif (memilih apa yang tidak Anda inginkan). Solusi yang diterima di atas memungkinkan pendekatan positif atau negatif.
Pierre-Olivier Vares
0

Gunakan git format-patchuntuk memotong bagian dari komit yang Anda pedulikan dan git ammenerapkannya ke cabang lain

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch
adrock20
sumber