Pertanyaan Bagaimana secara selektif menggabungkan atau memilih perubahan dari cabang lain di Git?


Saya menggunakan git pada proyek baru yang memiliki dua cabang paralel - tetapi saat ini eksperimental - pengembangan:

  • master: impor basis kode yang ada ditambah beberapa mod yang saya yakin
  • exp1: cabang percobaan # 1
  • exp2: cabang percobaan # 2

exp1 dan exp2 mewakili dua pendekatan arsitektur yang sangat berbeda. Sampai saya mendapatkan lebih jauh sepanjang saya tidak memiliki cara mengetahui yang mana (jika baik) akan bekerja. Ketika saya membuat kemajuan di satu cabang saya terkadang memiliki pengeditan yang akan berguna di cabang lain dan ingin menggabungkannya saja.

Apa cara terbaik untuk menggabungkan perubahan selektif dari satu cabang pengembangan ke cabang yang lain sambil meninggalkan yang lain?

Pendekatan yang telah saya pertimbangkan:

  1. git merge --no-commit diikuti oleh manual unstaging dari sejumlah besar pengeditan yang saya tidak ingin membuat kesamaan antara cabang-cabang.

  2. Manual menyalin file-file umum ke direktori temp diikuti oleh git checkout untuk pindah ke cabang lain dan kemudian menyalin lebih manual dari direktori temp ke dalam pohon kerja.

  3. Variasi di atas. Abaikan saja exp cabang untuk saat ini dan menggunakan dua repositori lokal tambahan untuk eksperimen. Ini membuat penyalinan manual dari file jauh lebih mudah.

Ketiga pendekatan ini tampaknya membosankan dan rawan kesalahan. Saya berharap ada pendekatan yang lebih baik; sesuatu yang mirip dengan parameter path filter yang akan dibuat git-merge lebih selektif.


1158
2018-01-16 04:55


asal


Jawaban:


Anda menggunakan cherry-pick perintah untuk mendapatkan komitmen individu dari satu cabang.

Jika perubahan yang Anda inginkan tidak dalam komitmen individual, maka gunakan metode yang ditunjukkan di sini membagi komit menjadi komitmen individu. Secara kasar, Anda gunakan git rebase -i untuk mendapatkan komit asli untuk mengedit, lalu git reset HEAD^ untuk secara selektif mengembalikan perubahan, lalu git commit untuk melakukan itu sebagai komitmen baru dalam sejarah.

Ada metode lain yang bagus di sini di Red Hat Magazine, di mana mereka gunakan git add --patch atau mungkin git add --interactive yang memungkinkan Anda untuk menambahkan hanya bagian-bagian dari suatu bingkisan, jika Anda ingin membagi berbagai perubahan ke file individual (cari di halaman itu untuk "split").

Setelah membagi perubahan, Anda sekarang dapat memilih yang Anda inginkan.


390
2018-01-16 06:01



Saya memiliki masalah yang sama persis seperti yang disebutkan oleh Anda di atas. Tapi saya menemukan ini lebih jelas dalam menjelaskan jawabannya.

Ringkasan:

  • Checkout path (s) dari cabang yang ingin Anda gabungkan,

    $ git checkout source_branch -- <paths>...
    
  • atau untuk menggabungkan hunun secara selektif

    $ git checkout -p source_branch -- <paths>...
    

    Atau, gunakan ulang dan kemudian tambahkan dengan opsi -p,

    $ git reset <paths>...
    $ git add -p <paths>...
    
  • Akhirnya berkomitmen

    $ git commit -m "'Merge' these changes"
    

816
2017-09-03 08:48



Untuk secara selektif menggabungkan file dari satu cabang ke cabang lain, jalankan

git merge --no-ff --no-commit branchX

dimana branchX adalah cabang yang ingin Anda gabungkan dari ke dalam cabang saat ini.

Itu --no-commit opsi akan menampilkan file yang telah digabung oleh Git tanpa benar-benar mencapainya. Ini akan memberi Anda kesempatan untuk memodifikasi file yang digabungkan, namun Anda menginginkannya dan kemudian melakukannya sendiri.

Bergantung pada bagaimana Anda ingin menggabungkan file, ada empat kasus:

1) Anda ingin gabungan yang benar.

Dalam hal ini, Anda menerima file yang digabungkan dengan cara Git menggabungkannya secara otomatis dan kemudian melakukannya.

2) Ada beberapa file yang tidak ingin Anda gabungkan.

Misalnya, Anda ingin mempertahankan versi di cabang saat ini dan mengabaikan versi di cabang yang Anda gabungkan.

Untuk memilih versi di cabang saat ini, jalankan:

git checkout HEAD file1

Ini akan mengambil versi dari file1 di cabang saat ini dan menimpanya file1 dikerjakan oleh Git.

3) Jika Anda ingin versi di branchX (dan bukan true merge).

Menjalankan:

git checkout branchX file1

Ini akan mengambil versi dari file1 di branchX dan menimpa file1 digabung otomatis oleh Git.

4) Kasus terakhir adalah jika Anda ingin memilih hanya gabungan tertentu dalam file1.

Dalam hal ini, Anda dapat mengedit yang dimodifikasi file1 langsung, perbarui ke versi apa pun yang Anda inginkan file1 menjadi, lalu berkomitmen.

Jika Git tidak dapat menggabungkan file secara otomatis, ia akan melaporkan file sebagai "tidak diganggu"dan menghasilkan salinan di mana Anda perlu menyelesaikan konflik secara manual.



Untuk menjelaskan lebih lanjut dengan sebuah contoh, katakanlah Anda ingin menggabungkan branchX ke dalam cabang saat ini:

git merge --no-ff --no-commit branchX

Anda kemudian jalankan git status perintah untuk melihat status file yang dimodifikasi.

Sebagai contoh:

git status

# On branch master
# Changes to be committed:
#
#       modified:   file1
#       modified:   file2
#       modified:   file3
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      file4
#

Dimana file1, file2, dan file3 apakah file git telah berhasil digabung otomatis.

Apa ini artinya adalah perubahan dalam master dan branchX karena ketiga file itu telah digabungkan bersama tanpa konflik apa pun.

Anda dapat memeriksa bagaimana penggabungan dilakukan dengan menjalankan git diff --cached;

git diff --cached file1
git diff --cached file2
git diff --cached file3

Jika Anda menemukan beberapa penggabungan yang tidak diinginkan, maka Anda bisa

  1. edit file secara langsung
  2. menyimpan
  3. git commit

Jika Anda tidak ingin bergabung file1 dan ingin mempertahankan versi di cabang saat ini

Menjalankan

git checkout HEAD file1

Jika Anda tidak ingin bergabung file2 dan hanya ingin versi di branchX

Menjalankan

git checkout branchX file2

jika kamu mau file3 untuk digabung secara otomatis, jangan lakukan apa pun.

Git telah menggabungkannya pada titik ini.


file4 di atas adalah penggabungan gagal oleh Git. Ini berarti ada perubahan di kedua cabang yang terjadi pada baris yang sama. Di sinilah Anda perlu menyelesaikan konflik secara manual. Anda dapat membuang penggabungan yang dilakukan dengan mengedit file secara langsung atau menjalankan perintah checkout untuk versi di cabang yang Anda inginkan file4 untuk menjadi.


Akhirnya, jangan lupa git commit.


239
2018-05-21 03:00



Saya tidak suka pendekatan di atas. Menggunakan cherry-pick sangat bagus untuk memilih satu perubahan, tetapi itu menyakitkan jika Anda ingin membawa semua perubahan kecuali untuk beberapa yang buruk. Inilah pendekatan saya.

Tidak ada --interactive Argumen Anda bisa lewat ke git bergabung.

Inilah alternatifnya:

Anda memiliki beberapa perubahan dalam fitur 'cabang' dan Anda ingin membawa beberapa tetapi tidak semuanya ke 'master' dengan cara yang tidak ceroboh (Anda tidak ingin memilih dan melakukan masing-masing)

git checkout feature
git checkout -b temp
git rebase -i master

# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change

# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

git checkout master
git pull . temp
git branch -d temp

Jadi, lilitkan saja dalam skrip shell, ubah master menjadi $ ke dan ubah fitur menjadi $ dari dan Anda siap untuk:

#! /bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp

85
2017-08-28 18:47



Ada cara lain, yaitu:

git checkout -p

Ini adalah campuran antara git checkout dan git add -p dan mungkin persis apa yang Anda cari:

   -p, --patch
       Interactively select hunks in the difference between the <tree-ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree-ish> was specified, the index).

       This means that you can use git checkout -p to selectively discard
       edits from your current working tree. See the “Interactive Mode”
       section of git-add(1) to learn how to operate the --patch mode.

73
2017-08-25 01:31



Sementara beberapa jawaban ini cukup bagus, saya merasa tidak ada jawaban kendala asli OP: memilih file tertentu dari cabang tertentu. Solusi ini melakukan itu, tetapi mungkin membosankan jika ada banyak file.

Katakanlah Anda memiliki master, exp1, dan exp2 ranting. Anda ingin menggabungkan satu file dari masing-masing cabang eksperimental ke dalam master. Saya akan melakukan sesuatu seperti ini:

git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b

# save these files as a stash
git stash
# merge stash with master
git merge stash

Ini akan memberi Anda diff dalam file untuk setiap file yang Anda inginkan. Tidak ada lagi. Tidak kurang. Ini berguna Anda memiliki perubahan file yang sangat berbeda antara versi - dalam kasus saya, mengubah aplikasi dari Rails 2 ke Rails 3.

EDIT: ini akan menggabungkan file, tetapi melakukan penggabungan cerdas. Saya tidak dapat mengetahui cara menggunakan metode ini untuk mendapatkan informasi dalam file diff (mungkin itu masih akan untuk perbedaan ekstrim. Mengganggu hal-hal kecil seperti spasi dapat digabung kembali kecuali jika Anda menggunakan -s recursive -X ignore-all-space pilihan)


48
2018-05-07 11:38



1800 Jawaban INFORMASI benar sepenuhnya. Sebagai git noob, meskipun, "menggunakan git cherry-pick" tidak cukup bagi saya untuk mengetahui hal ini tanpa sedikit menggali di internet, jadi saya pikir saya akan memposting panduan yang lebih rinci jika orang lain berada dalam perahu yang sama.

Kasus penggunaan saya ingin secara selektif menarik perubahan dari cabang github orang lain ke dalam cabang saya sendiri. Jika Anda sudah memiliki cabang lokal dengan perubahan, Anda hanya perlu melakukan langkah 2 dan 5-7.

  1. Buat (jika tidak dibuat) cabang lokal dengan perubahan yang Anda inginkan.

    $ git branch mybranch <base branch>

  2. Beralihlah ke dalamnya.

    $ git checkout mybranch

  3. Tarik perubahan yang Anda inginkan dari akun orang lain. Jika Anda belum melakukannya, Anda akan ingin menambahkannya sebagai remote.

    $ git remote add repos-w-changes <git url>

  4. Tarik semuanya dari dahannya.

    $ git pull repos-w-changes branch-i-want

  5. Lihat log commit untuk melihat perubahan yang Anda inginkan:

    $ git log 

  6. Beralih kembali ke cabang yang ingin Anda tarik perubahannya.

    $ git checkout originalbranch

  7. Cherry memilih komit Anda, satu demi satu, dengan hash.

    $ git cherry-pick -x hash-of-commit

Kiat topi: http://www.sourcemage.org/Git_Guide


42
2017-07-29 08:37



Di sini adalah bagaimana Anda dapat mengganti Myclass.java file di master cabang dengan Myclass.java di feature1 cabang. Itu akan berfungsi bahkan jika Myclass.java tidak ada di master.

git checkout master
git checkout feature1 Myclass.java

Catatan ini akan menimpa - tidak menggabungkan - dan mengabaikan perubahan lokal di cabang master.


37
2018-02-27 22:42