Git'teki başka bir şubedeki değişiklikleri seçici olarak nasıl birleştirir veya alır?


1450

Git'i iki paralel - şu anda deneysel - geliştirme dalı olan yeni bir projede kullanıyorum:

  • master: mevcut kod tabanı ve genellikle emin olduğum birkaç mod içe aktarma
  • exp1: deneysel şube # 1
  • exp2: deneysel dal # 2

exp1ve exp2çok farklı iki mimari yaklaşımı temsil ediyor. Daha ileri gidene kadar hangisinin çalışacağını bilmem mümkün değil. Bir dalda ilerleme kaydettiğimde bazen diğer dalda yararlı olacak ve sadece bunları birleştirmek isteyen düzenlemelerim olur.

Diğer her şeyi geride bırakırken bir geliştirme dalından diğerine seçici değişiklikleri birleştirmenin en iyi yolu nedir?

Düşündüğüm Yaklaşımlar:

  1. git merge --no-commit ardından şubeler arasında ortak yapmak istemediğim çok sayıda düzenlemenin manuel olarak işaretlenmemiş olması.

  2. Ortak dosyaların bir geçici dizine git checkoutelle kopyalanması ve ardından diğer şubeye taşınması ve daha sonra geçici dizinden çalışma ağacına daha manuel olarak kopyalanması.

  3. Yukarıda bir varyasyon. expŞimdilik dalları terk edin ve deneme için iki ek yerel depo kullanın. Bu, dosyaların manuel olarak kopyalanmasını çok daha kolay hale getirir.

Bu yaklaşımların üçü de sıkıcı ve hataya açık görünüyor. Daha iyi bir yaklaşım olduğunu umuyorum; git-mergedaha seçici hale getirecek bir filtre yolu parametresine benzeyen bir şey .


5
Deneysel dallarınızdaki değişiklikler ayrı taahhütlerde iyi organize edilmişse , seçici dosyalar yerine seçici taahhütlerin birleştirilmesi açısından düşünmek daha iyidir . Aşağıdaki cevapların çoğu bunun böyle olduğunu varsayar.
akaihola

2
Bunu git merge -s ours --no-committakip eden bir kombinasyon git read-treebunun için iyi bir çözüm olmaz mı? Bkz. Stackoverflow.com/questions/1214906/…
VonC

34
Daha yeni bir sorunun tek satırlık, iyi yazılmış bir cevabı var: stackoverflow.com/questions/10784523/…
brahn

Yalnızca belirli dosyaları birleştirmek için bu bloga göz atın jasonrudolph.com/blog/2009/02/25/…
Ashutosh Chamoli

Yanıtlar:


475

Bir daldan bireysel taahhütler almak için cherry-pick komutunu kullanırsınız.

İstediğiniz değişiklikler bireysel taahhütlerde değilse, taahhüdü bireysel taahhütlere ayırmak için burada gösterilen yöntemi kullanın . Kabaca konuşmak gerekirse, git rebase -iorijinal düzenleme taahhüdünü almak, daha sonra git reset HEAD^değişiklikleri seçici olarak geri döndürmek, daha sonra git commitbu biti tarihte yeni bir taahhüt olarak işlemek için kullanırsınız.

Burada , Red Hat Magazine'de, tek bir dosyaya farklı değişiklikleri bölmek istiyorsanız ( git add --patchmuhtemelen git add --interactive"bölme" için arama yapın), kullandıkları veya muhtemelen bir parçanın sadece parçalarını eklemenize izin veren başka bir güzel yöntem daha vardır .

Değişiklikleri böldükten sonra, artık sadece istediğinizi seçebilirsiniz.


14
Anladığım kadarıyla, bu daha yüksek oy alan cevaptan gereksiz yere daha kıvrımlı.
Alexander Bird

54
Bu teknik olarak doğru cevaptır, doğru cevap "kıvrık" olarak görünür. --- Yüksek oylanan cevap hızlı ve kirli bir "hile yapar" yanıtı, hangi çoğu insan hakkında tüm (:
Jacob

3
@akaihola: HEAD ^ doğru. Bkz. ^ Notasyonu öneki, bir taahhütten erişilebilen taahhütleri hariç tutmak için kullanılır.
Tyler Rick

13
Sadece en temiz ve daha az kıvrımlı görünen başka bir yaklaşımı paylaşmak istedim: jasonrudolph.com/blog/2009/02/25/… toplam basitlik ve harika
superuseroi

14
Hangi yaklaşımın 'doğru' olduğu konusundaki tartışmalarla karıştırılmamalıdır? Dosyalar ve taahhütler arasındaki farkı göz önünde bulundurun (bkz. Alttaki Açıklamalar) . OP, DOSYALARI birleştirmek istiyor ve KOMİTELERDEN bahsetmiyor. Daha yüksek oy kullanan cevap dosyalara özgüdür; kabul edilen cevap, taahhütlere özgü kiraz toplama kullanır. Kiraz toplama, seçici olarak birleştirme işlemleri için anahtar olabilir, ancak dosyaları bir şubeden diğerine taşımak için çok acı verici olabilir. Taahhütler git'in gücünün kalbi olmasına rağmen, dosyaların hala bir rolü olduğunu unutmayın!
Kay V

970

Yukarıda belirttiğinizle aynı problemi yaşadım. Ama cevabı açıklarken bunu daha net buldum .

Özet:

  • Birleştirmek istediğiniz şubeden yollara göz atın,

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

    İpucu: Bağlantılı gönderide --görülmediği gibi çalışır .

  • veya iri parçaların seçici olarak birleştirilmesi

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

    Alternatif olarak, reset'i kullanın ve ardından seçenekle ekleyin -p,

    $ git reset <paths>...
    $ git add -p <paths>...
    
  • Sonunda taahhüt

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

9
Bart J'nin bağlantılı makalesi en iyi yaklaşımdır. Açık, basit, tek bir komut. Kullanmak üzereyim. :)
Pistos

256
Bu gerçek bir birleşme değil. Değişiklikleri taahhüt yerine dosyaya göre seçiyorsunuz ve mevcut taahhüt bilgilerini (yazar, mesaj) kaybedeceksiniz. Bazı dosyalardaki tüm değişiklikleri birleştirmek istiyorsanız bu iyidir ve tüm taahhütleri yeniden yapmanız gerekir. Ancak dosyalar hem birleştirilecek değişiklikleri hem de atılacak diğerlerini içeriyorsa, diğer yanıtlarda sağlanan yöntemlerden biri size daha iyi hizmet edecektir.
akaihola

10
@mykhal ve diğerleri: bu teslim eğer size bu yüzden, otomatik endekste dosyaları aşamalarında foo.cyapmak git reset HEAD foo.cbu dosyayı unstage için ve bunu daha sonra diff yapabilirsiniz. Bunu denedikten ve buraya bir cevap aramak için buraya geldikten sonra buldum
michiakig

12
Ayrıca kullanabileceğiniz değişiklikleri görmek için:git diff --cached
OderWat

9
Bu cevaba göre git checkout -p <revision> -- <path>tarif ettiğiniz ilk üç komutu
vermekle

338

Dosyaları bir şubeden başka bir şubeye seçici olarak birleştirmek için,

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

branchXgeçerli şubeyle birleştirmek istediğiniz dal nerede .

Bu --no-commitseçenek Git tarafından birleştirilen dosyaları gerçekte işlemeden yerleştirir. Bu, birleştirilen dosyaları istediğiniz gibi değiştirme ve daha sonra bunları kendiniz yapma fırsatı verecektir.

Dosyaları nasıl birleştirmek istediğinize bağlı olarak, dört durum vardır:

1) Gerçek bir birleşme istiyorsun.

Bu durumda, birleştirilmiş dosyaları Git'in otomatik olarak birleştirme biçimini kabul edersiniz ve sonra bunları taahhüt edersiniz.

2) Birleştirmek istemediğiniz bazı dosyalar var.

Örneğin, sürümü geçerli dalda tutmak ve birleştirdiğiniz daldaki sürümü yok saymak istersiniz.

Geçerli daldaki sürümü seçmek için şunu çalıştırın:

git checkout HEAD file1

Bu işlem file1, geçerli daldaki sürümünü alır ve file1Git tarafından otomatikleştirilenin üzerine yazar .

3) BranchX sürümü (ve gerçek bir birleştirme değil) istiyorsanız.

Çalıştırmak:

git checkout branchX file1

Bu sürümünü alır file1içinde branchXve üzerine yazma file1Git tarafından otomatik olarak birleşti.

4) Son durum, içinde yalnızca belirli birleştirme seçmek istiyorsanız file1.

Bu durumda, değiştirilmiş file1olanı doğrudan düzenleyebilir , sürümünün olmasını istediğiniz her şeye güncelleyebilir file1ve sonra taahhütte bulunabilirsiniz.

Git bir dosyayı otomatik olarak birleştiremezse , dosyayı " birleştirilmemiş " olarak bildirir ve çakışmaları manuel olarak çözmeniz gereken bir kopya oluşturur.



Bir örnekle daha ayrıntılı açıklamak için, diyelim ki branchXmevcut dalla birleştirmek istiyorsunuz :

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

Daha sonra git statusdeğiştirilen dosyaların durumunu görüntülemek için komutu çalıştırın .

Örneğin:

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
#

Nerede file1,, file2ve file3git dosyaları başarıyla otomatik olarak birleştirildi.

Bunun anlamı, bu üç dosyadaki masterve branchXtüm dosyalardaki değişikliklerin herhangi bir çakışma olmadan bir araya getirilmesidir.

Birleştirmenin nasıl yapıldığını git diff --cached;

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

İstenmeyen birleşme bulursanız,

  1. dosyayı doğrudan düzenle
  2. kayıt etmek
  3. git commit

file1Sürümü birleştirmek istemiyorsanız ve sürümü geçerli dalda tutmak istiyorsanız

Çalıştırmak

git checkout HEAD file1

Birleştirmek file2istemiyorsanız ve yalnızca sürümübranchX

Çalıştırmak

git checkout branchX file2

file3Otomatik olarak birleştirilmek istiyorsanız , hiçbir şey yapmayın.

Git zaten bu noktada birleştirdi.


file4Yukarıdaki Git tarafından başarısız bir birleştirme. Bu, her iki dalda da aynı satırda meydana gelen değişiklikler olduğu anlamına gelir. Bu, çakışmaları manuel olarak çözmeniz gereken yerdir. Dosyayı doğrudan düzenleyerek veya olmak istediğiniz daldaki sürümün ödeme komutunu çalıştırarak yapılan birleştirmeyi atabilirsiniz file4.


Son olarak, unutmayın git commit.


10
Yine de dikkatli olun: Eğer git merge --no-commit branchXsadece bir hızlı ileri ise, işaretçi güncellenir ve --no-commit sessizce göz ardı edilir
cfi

16
@cfi --no-ffBu davranışı önlemek için eklemeye ne dersiniz ?
Eduardo Costa

5
Kesinlikle bu cevabı Eduardo'nun "--no-ff" seçeneği ile güncellemenizi öneririz. Sadece benim birleştirme hızlı ileri almak için (aksi takdirde büyük) her şeyi okudum.
Funktr0n

7
Bu çözüm en iyi sonuçları ve esnekliği sağlar.
Thiago Macedo

20
En çok oy alan cevabın aksine, bu çözüm benim için önemli olan birleşme tarihimi korudu. Diğer önerilen tüm çözümleri denemedim, belki de bazıları da bunu yapıyor.
ws_e_c421

107

Yukarıdaki yaklaşımları sevmiyorum. Kiraz toplama tek bir değişiklik seçmek için harika, ancak bazı kötü olanlar hariç tüm değişiklikleri getirmek istiyorsanız bir acıdır. İşte yaklaşımım.

--interactiveGit merge'ye iletebileceğiniz hiçbir argüman yok .

İşte alternatif:

Şube 'özelliğinde' bazı değişiklikleriniz var ve hepsini değil, bazılarını özensiz olmayan bir şekilde 'ustalığa' getirmek istiyorsunuz (yani her birini kiraz almak ve işlemek istemiyorsunuz)

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

Bu yüzden bir kabuk betiğine sarın, ustayı $ olarak değiştirin ve özelliği $ 'dan değiştirin ve gitmekte fayda var:

#!/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

Biçimlendirmeyi düzelttim - taahhütlerin bir seçimini yapmak istiyorsanız bu oldukça güzel bir yöntem
1800 BİLGİ

Bu tekniği şimdi kullanıyorum ve gerçekten iyi çalışıyor gibi görünüyor.
dylanfm

4
Sen değiştirmek isteyebilirsiniz git rebase -i $toiçin git rebase -i $to || $SHELLkullanıcı çağırabilir böylece, git --skipRebase başarısız olursa gerektiği şekilde, vb. Ayrıca &&yeni satırlar yerine satırları zincirlemeye değer .
sircolinton

2
Ne yazık ki, cevaptaki bağlantı öldü.
ThomasW

Bağlantı sadece ölü değil, aynı zamanda WOT kötü itibar uyarısına sahiptir. Bu yüzden kaldırdım.
Jean-François Corbett

93

Başka bir yol var:

git checkout -p

Bu git checkoutve arasında bir karışımdır ve git add -ptam olarak aradığınız şey olabilir:

   -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.

10
Bu, birleştirilecek çok sayıda yönetilebilir değişiklikiniz olduğu sürece, en kolay, en basit yöntemdir. Umarım daha fazla insan bu yanıtı fark edip onaylayacaktır. Örnek: git checkout --patch exp1 file_to_merge
Tyler Rick

1
Bu soruya benzer cevap gönderildi: stackoverflow.com/a/11593308/47185
Tyler Rick

Oh, kasada bir yama olduğunu bilmiyordum! Bunun yerine ödeme / reset / add -p yaptım.
Daniel C.Sobral

2
Gerçekten en basit yöntem. git checkout -p özellik dosya adı. Ve en iyi şey komut çalıştırıldığında, size ay / n / e /? / ... vb. dosyanın nasıl birleştirileceğine karar verme seçeneği. E ile denedim ve yamayı uygulamadan önce bile düzenleyebilirim ... Ne kadar havalı. Diğer dallardan seçmeli dosyaları birleştirmek için gerçek bir astar.
infoclogged

55

Bu cevaplardan bazıları oldukça iyi olsa da, hiçbirinin OP'nin orijinal kısıtlamasına aslında cevap vermediğini hissediyorum: belirli dallardan belirli dosyaları seçmek. Bu çözüm bunu yapar, ancak çok sayıda dosya varsa sıkıcı olabilir.

Sahip Sağlar ki master, exp1ve exp2dalları. Deneysel dalların her birinden bir dosyayı master'a birleştirmek istiyorsunuz. Böyle bir şey yapardım:

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

Bu, istediğiniz her dosya için size dosya içi farklılıklar verecektir. Başka bir şey yok. Daha az değil. Sürümler arasında kökten farklı dosya değişiklikleriniz olması yararlıdır - benim durumumda, bir uygulamayı Rails 2'den Rails 3'e değiştirmek.

EDIT : Bu dosyaları birleştirir, ancak akıllı birleştirme yapar. Ben de dosya fark bilgileri almak için bu yöntemi kullanmak anlamaya mümkün değildi (belki hala aşırı farklılıkların. Boşluk get gibi sinir bozucu küçük şeyler geri kullandığınız sürece birleşen olacaktır -s recursive -X ignore-all-spaceseçeneği)


4
Ayrıca not: belirli bir şubeden tüm satır içi birden fazla dosya yapabilirsiniz, örneğingit checkout exp1 path/to/file_a path/to/file_x
EMiller

2
Bu güzel. git checkout feature <path>/*Dosya grupları elde ettim .
Isherwood

Bu iyi çalışıyor, ancak iki ekstra taahhüt nesnesi eklendi. Değil büyük bir anlaşma ama biraz dağınık
MightyPork

@MightyPork haklısın. Ne yazık ki, bunu bu kadar uzun zaman önce yazdığım için, neden "git stash" ve "git merge stash" adımlarının neden "git commit" yerine orada olduğundan emin değilim.
Eric Hu

2
Oh, bu açık, sanırım. Bu şekilde, hedef daldaki önceki değişikliklerin üzerine yazılmasına gerek kalmadan tek bir dosyayı birleştirir.
MightyPork

48

1800 BİLGİ'nin yanıtı tamamen doğru. Git git çaylak olarak, "git kiraz-pick kullanın" benim için internette biraz daha kazma olmadan bunu anlamak için yeterli değildi, bu yüzden başka bir durumda olması durumunda daha ayrıntılı bir rehber yayınlamak düşündüm benzer tekne.

Benim kullanım durumum, bir başkasının github şubesinden değişiklikleri kendime seçici olarak çekmek istiyordu. Değişikliklerin olduğu bir yerel şubeniz varsa, yalnızca 2. ve 5-7. Adımları uygulamanız gerekir.

  1. Getirmek istediğiniz değişikliklerle yerel bir şube oluşturun (oluşturulmamışsa).

    $ git branch mybranch <base branch>

  2. Buna geçin.

    $ git checkout mybranch

  3. Diğer kişinin hesabından istediğiniz değişiklikleri aşağı çekin. Henüz yapmadıysanız, onları uzaktan kumanda olarak eklemek istersiniz.

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

  4. Her şeyi dallarından aşağı çekin.

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

  5. İstediğiniz değişiklikleri görmek için taahhüt günlüklerini görüntüleyin:

    $ git log

  6. Değişiklikleri çekmek istediğiniz şubeye geri dönün.

    $ git checkout originalbranch

  7. Cherry, karmaları ile birer birer taahhütlerini seç.

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

Şapka ipucu: http://www.sourcemage.org/Git_Guide


3
İpucu: git cherryHenüz birleştirmediğiniz taahhütleri tanımlamak için önce komutu kullanın (önce kılavuza bakın).
akaihola

Bu çalışır .. 1. yeni bir şube yarattı 2. bazı dosyalar oluşturdu / bazı değişiklikler yaptı 3. taahhüt 4. ana şube ödeme 5. Çalıştır git cherry-pick -x hash-of-taahhüt ve birleştirme çatışmalarını çözmek iyidir gitmek.
RamPrasadBismil

Bağlantınız artık çalışmıyor. Lütfen güncelleyebilir misiniz?
creep3007

42

Şube içindeki Myclass.javadosyayı masterşube ile nasıl değiştirebileceğiniz aşağıda açıklanmıştır . Üzerinde olmasa bile çalışır .Myclass.javafeature1Myclass.javamaster

git checkout master
git checkout feature1 Myclass.java

Bunun, ana daldaki yerel değişikliklerin üzerine yazacağını - birleştirilmeyeceğini - ve yok sayacağını unutmayın.


6
Bu birleşmeyecek. Sadece master1'deki özelliğin, feature1 dalındaki değişikliklerin üzerine yazacaktır.
Skunkwaffle

3
Mükemmel bir şekilde, theirsüzerine yazılan bu tür birleşme arıyordum ours=> +1 Şerefe;)
olibre

1
Bazı zamanlarda yapmak istediğiniz tek şey tüm dosyayı değiştirmek, bu yüzden istediğim budur, ancak bu dosyada yaptığınız tüm değişiklikleri kaybetmek istediğinizden emin olmanız gerekir.
MagicLAMP

1
OP'nin tüm dosyayı özel olarak başka bir daldaki eşdeğeriyle değiştirmek istediği göz önüne alındığında en temiz çözüm:2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
Brent Faust

29

Basit bir şekilde, belirli dosyaları iki daldan birleştirmek , sadece belirli dosyaları başka bir daldan olanlarla değiştirmek değildir.

Birinci adım: Dalları farklılaştırın

git diff branch_b > my_patch_file.patch

Geçerli dal ile branch_b arasındaki farkın bir yama dosyasını oluşturur

İkinci adım: Yamayı bir kalıpla eşleşen dosyalara uygulayın

git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch

seçenekler hakkında faydalı notlar

*Dahil etme deseninde joker karakter olarak kullanabilirsiniz .

Eğik çizgiler kaçmak zorunda değildir.

Ayrıca, bunun yerine --exclude komutunu kullanabilir ve kalıpla eşleşen dosyalar dışındaki her şeye uygulayabilir veya yamayı -R ile tersine çevirebilirsiniz

-P1 seçeneği, * unix yama komutundan bir ayırma ve yama dosyasının içeriğinin her dosya adının başına a/veyab/ (veya düzeltme eki dosyasının nasıl oluşturulduğuna bağlı olarak) gerekir. yamanın uygulanması gereken dosyanın yolunun gerçek dosyası.

Daha fazla seçenek için git-uygulamak için kılavuz sayfasına göz atın.

Üçüncü adım: Üçüncü adım yoktur

Açıkçası değişikliklerinizi yapmak istersiniz, ancak kim taahhütte bulunmadan önce yapmak istediğiniz ilgili diğer ayarların olmadığını söyler.


1
Bu, current_branch'ın korunması gereken çok sayıda "ek" değişikliğe sahip olduğu durumlarda çok kullanışlıdır. Sadece branch_b tarafından getirilen değişikliklerin farkını aldım: git diff HEAD ... branch_b (evet - üç periyot sihir numarası yapar).
Saad Malik

@masukomi, 2. adımda, 1. adımda oluşturulan yama dosyasını bağımsız değişken olarak eklememeniz gerekir mi?
Spiralis

Benim için tüm değişiklikler reddedildi. Neden olduğu hakkında bir fikrin var mı?
LinusGeffarth

İlk düşünce @LinusGeffarth, yamayı yaparken şubeleri geri almanızdır. anlayabileceğimizi görmek için SO dışında takip edecek.
masukomi

24

Daha "basit" bir birleştirme istemediğiniz çok daha fazla değişiklik getirmiş olsa bile, tarihin en az yaygara ile başka bir şubeden sadece birkaç dosyayı takip etmesini nasıl sağlayabilirsiniz.

İlk olarak, gitmeye çalıştığınız şeyin birleştirme olduğunu önceden bildirmek için alışılmadık bir adım atacaksınız, git çalışma dizininizdeki dosyalara hiçbir şey yapmadan:

git merge --no-ff --no-commit -s ours branchname1

. . . burada "branchname", birleştirme talebinde bulunduğunuz şeydir. Eğer derhal taahhütte bulunacak olsaydınız, hiçbir değişiklik yapmazdı ama yine de diğer şubeden soy atalarını gösterirdi. Daha fazla şube / etiket / vb. Ekleyebilirsiniz. komut satırına da ihtiyacınız varsa. Bu noktada, taahhüt edilecek değişiklik yok, bu yüzden dosyaları diğer revizyonlardan alın.

git checkout branchname1 -- file1 file2 etc

Birden fazla şubeden birleştirme yapıyorsanız, gerektiği kadar tekrarlayın.

git checkout branchname2 -- file3 file4 etc

Şimdi diğer şubedeki dosyalar, dizinde, işlenmeye hazır, geçmişle birlikte.

git commit

ve bu taahhüt mesajında ​​yapacak çok şey açıklayacaksınız.

Ancak, net olmadığı takdirde, bunun yapılması gereken bir şey olduğunu lütfen unutmayın. Bu bir "dalın" ne için olduğu ruhu içinde değildir ve kiraz toplama burada yapacağınız şeyi yapmanın daha dürüst bir yoludur. Aynı şubede son kez getirmediğiniz diğer dosyalar için başka bir "birleştirme" yapmak istiyorsanız, "zaten güncel" bir mesajla sizi durduracaktır. Bu olması gerektiğinde dallanmama belirtisi, "from" dalında birden fazla farklı dal olmalıdır.


3
İlk komutunuz ( git merge --no-ff --no-commit -s outs branchname1) tam da aradığım şey! Teşekkürler!
RobM

1
Birden fazla dalı, gerekli geçmişi, tek dosyaları birleştirmek ve itmeden önce dosyanın içeriğini değiştirmek zorunda, bu iyi bir alternatif gibi görünüyor. Örneğin dev => master, ancak master'a geçmeden önce bir ana makine tanımını veya benzerini değiştirmek istersiniz.
timss

15

Biraz geç kaldığımı biliyorum ama bu, seçici dosyaları birleştirmek için iş akışım.

#make a new branch ( this will be temporary)
git checkout -b newbranch
# grab the changes 
git merge --no-commit  featurebranch
# unstage those changes
git reset HEAD
(you can now see the files from the merge are unstaged)
# now you can chose which files are to be merged.
git add -p
# remember to "git add" any new files you wish to keep
git commit

Bu konuda küçük bir varyasyon kullandım. Birleştirmek yerine kiraz topladım. İşi yapıyor. Bu yaklaşımın tek dezavantajı, orijinal işlem karması referansını kaybetmenizdir.
Matt Florence

15

En kolay yol, repoyu birleştirmek istediğiniz şubeye ayarlamak ve ardından çalıştırmaktır,

git checkout [branch with file] [path to file you would like to merge]

Eğer koşarsan

git status

dosyanın önceden sahnelendiğini göreceksiniz ...

O zaman koş

git commit -m "Merge changes on '[branch]' to [file]"

Basit.


3
Bu neredeyse bulduğum en iyi cevap. lütfen bakınız jasonrudolph.com/blog/2009/02/25/… Çok açık, özlü ve işe yarıyor!
superuseroi

1
birleştirmek yerine kaynak daldaki dosya içeriğini tamamen değiştirecek
Amare

Bu şekilde cevaplamak üzereydim, henüz cevaplanmayan yeni şeyler icat ettiğimi sanıyordum! Ama bunu yapmanın en basit yolu bu. Bu üstte olmalı!
Irfandy Jip

15

Bu yazıyı en basit cevabı içermek için buldum . Sadece şunları yapın:

$ #git checkout <branch from which you want files> <file paths>

Misal:

$ #pulling .gitignore file from branchB into current branch
$ git checkout branchB .gitignore

Daha fazla bilgi için yayına bakın.


3
Bu gerçekten birleşmez, geçerli daldaki dosyanın üzerine yazar.
Igor Ralic

1
@igrali Bu yararlı bir yorum, ancak bunu yapmanın "uygun" yollarının zorluğu ile karşılaştırıldığında, bu iyi bir çözüm. Biri çok dikkatli olmalı.
owensmartin

12

Git'in hala "kutudan çıkmış" gibi kullanışlı bir araca sahip olmaması garip. Geçerli sürüm dalından bazı hata düzeltmeleri ile bazı eski sürüm dalını (hala birçok yazılım kullanıcısı var) güncellerken yoğun olarak kullanıyorum . Bu durumda , bagajdaki dosyadan sadece bazı kod satırlarını hızlı bir şekilde almak, çoğu eski değişikliği görmezden gelmek gerekir (eski sürüme girmesi gerekmez) ... Ve elbette etkileşimli üç yönlü birleştirme bu durumda gereklidir, git checkout --patch <branch> <file path>bu seçici birleştirme amacıyla kullanılamaz.

Kolayca yapabilirsiniz:

Bu satırı [alias]genel .gitconfigveya yerel .git/configdosyanızdaki bölüme eklemeniz yeterlidir:

[alias]
    mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; /C/BCompare3/BCompare.exe $2.theirs $2 $2.base $2; rm -f $2.theirs; rm -f $2.base;' -"

Bu, Beyond Compare'i kullandığınız anlamına gelir. Gerekirse istediğiniz yazılımı değiştirmeniz yeterlidir. Veya etkileşimli seçici birleştirmeye ihtiyacınız yoksa üç yönlü otomatik birleştirme olarak değiştirebilirsiniz:

[alias]
    mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; git merge-file $2 $2.base $2.theirs; rm -f $2.theirs; rm -f $2.base;' -"

Sonra şöyle kullanın:

git mergetool-file <source branch> <file path>

Bu, diğer daldaki herhangi bir dosyanın gerçek seçici ağaç yolu birleştirme fırsatını verecektir .


10

Tam olarak aradığınız şey değil, ama benim için yararlı oldu:

git checkout -p <branch> -- <paths> ...

Bazı cevapların bir karışımıdır.


2
Bu gerçekten kullanışlıdır ve benim için en iyi cevaba, @ alvinabad'ın cevabına eklenebilir. Bunu yaparken: git checkout HEAD file1geçerli sürümü korumak ve dosyanın birleştirmesini kaldırmak için, birleştirilecek dosyanın bir kısmını seçmek file1için -pseçenek kullanılabilir . hile için teşekkürler!
Simon C.

Bu benim favori cevabım. Basit, noktaya ve çalışıyor
Jesse Reza Khorasanee

8

Yapardım

git diff commit1..commit2 dosya deseni | git-Apply --index && git kesin

Bu şekilde bir şubeden bir dosya deseninin taahhüt aralığını sınırlayabilirsiniz.

Çalınan: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html


Bazı durumlarda, bu çok kullanışlı olabilir. Bununla birlikte, değişiklikler farklı bir dalda ise, Bart J'nin yukarıdaki cevabında olduğu gibi, o dalın ucundan ödeme yapabilirsiniz.
cdunn2001

Bart Js kimdir?
Siyah

8

Yukarıda belirttiğinizle aynı problemi yaşadım. Ama bu git blogunu buldum cevabı açıklarken daha net .

Yukarıdaki bağlantıdan komut:

#You are in the branch you want to merge to
git checkout <branch_you_want_to_merge_from> <file_paths...>

bunu test ettin mi eminim dosyalar birleştirilmek yerine <branch_you_want_to_merge_from> yerine değiştirilecek
Amare

7

Yukarıdaki 'git-interactive-merge' cevabını beğendim, ama daha kolay bir tane var. Git etkileşimli ve üzerine bir rebase kombinasyonu kullanarak bunu sizin için yapalım:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o master

Yani durum C1 ve C2'yi 'özellik' dalından ('A' dallanma noktası) istiyor, ancak şimdilik geri kalanların hiçbirini istemiyorsunuz.

# git branch temp feature
# git checkout master
# git rebase -i --onto HEAD A temp

Bu, yukarıdaki gibi, C1 ve C2 için 'seçim' satırlarını seçtiğiniz interaktif düzenleyiciye bırakır (yukarıdaki gibi). Kaydedin ve çıkın, sonra rebase ile devam edecek ve size 'temp' dalını ve ayrıca master + C1 + C2'de HEAD verecektir:

      A---C1---o---C2---o---o feature
     /
----o---o---o---o-master--C1---C2 [HEAD, temp]

Daha sonra master'ı HEAD'e güncelleyebilir ve temp dalını silebilirsiniz ve gitmekte fayda var:

# git branch -f master HEAD
# git branch -d temp

7

Ne olmuş git reset --soft branch? Henüz kimsenin bahsetmediğine şaşırdım.

Benim için, değişiklikleri başka bir daldan seçerek almanın en kolay yolu, çünkü bu komut çalışma ağacımı koyar, tüm fark değişiklikleri ve ihtiyacım olanı kolayca seçebilir veya geri alabilirim. Bu şekilde, taahhüt edilen dosyalar üzerinde tam kontrole sahibim.


6

Bu sorunun eski olduğunu ve başka birçok cevap olduğunu biliyorum, ancak dizinleri kısmen birleştirmek için 'pmerge' adlı kendi senaryomu yazdım. Bu devam eden bir çalışma ve hala git ve bash komut dosyalarını öğreniyorum.

Bu komut, git merge --no-commitsağlanan yolla eşleşmeyen değişiklikleri kullanır ve ardından bu uygulamaları kaldırır.

Kullanımı: git pmerge branch path
örnek:git merge develop src/

Ben kapsamlı bir şekilde test etmedim. Çalışma dizininde, taahhüt edilmeyen değişiklikler ve izlenmeyen dosyalar bulunmamalıdır.

#!/bin/bash

E_BADARGS=65

if [ $# -ne 2 ]
then
    echo "Usage: `basename $0` branch path"
    exit $E_BADARGS
fi

git merge $1 --no-commit
IFS=$'\n'
# list of changes due to merge | replace nulls w newlines | strip lines to just filenames | ensure lines are unique
for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do
    [[ $f == $2* ]] && continue
    if git reset $f >/dev/null 2>&1; then
        # reset failed... file was previously unversioned
        echo Deleting $f
        rm $f
    else
        echo Reverting $f
        git checkout -- $f >/dev/null 2>&1
    fi
done
unset IFS

4

read-treeVerilen uzak ağacı geçerli dizine okumak veya birleştirmek için kullanabilirsiniz , örneğin:

git remote add foo git@example.com/foo.git
git fetch foo
git read-tree --prefix=my-folder/ -u foo/master:trunk/their-folder

Birleştirme gerçekleştirmek için şunu kullanın: -m kullanın.

Ayrıca bkz: git içindeki bir alt dizini nasıl birleştiririm?


3

Dosya ile seçici birleştirme / işleme için basit bir yaklaşım:

git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes


3

Değişen çok fazla dosyanız yoksa, bu size fazladan bir taahhüt vermez.

1. Şubeyi geçici olarak çoğaltın
$ git checkout -b temp_branch

2. Son istenen işleme sıfırlayın
$ git reset --hard HEAD~n , ngeri dönmeniz gereken taahhütlerin sayısı nerede?

3. Her dosyayı orijinal şubesinden teslim alma
$ git checkout origin/original_branch filename.ext

Artık gerekirse, uzaktan kumandanın üzerine yazmayı zorlayabilir ve zorlayabilirsiniz.


3

Yalnızca geçmişini korumak belirli dizin ve bırakın her şey sağlam birleştirme ve henüz gerekiyorsa, muhtemelen yeni oluşturmak ... Bu deneyebilirsiniz target-branchait kapalı masterdenemeler önce.

Aşağıdaki adımlarda iki dalınız olduğu target-branchve birleştirmek istediğiniz source-branchdizinin dir-to-mergeolduğu varsayılmaktadır source-branch. Ayrıca dir-to-retain, hedefte olduğu gibi , geçmişi değiştirmek ve saklamak istemediğiniz başka dizinlerin de olduğunu varsayın . Ayrıca, içinde birleşme çatışmaları olduğunu varsayar dir-to-merge.

git checkout target-branch
git merge --no-ff --no-commit -X theirs source-branch
# the option "-X theirs", will pick theirs when there is a conflict. 
# the options "--no--ff --no-commit" prevent a commit after a merge, and give you an opportunity to fix other directories you want to retain, before you commit this merge.

# the above, would have messed up the other directories that you want to retain.
# so you need to reset them for every directory that you want to retain.
git reset HEAD dir-to-retain
# verify everything and commit.

2

İki dalın geçerli taahhütleri arasında yalnızca birkaç dosya değiştiğinde, farklı dosyalardan geçerek değişiklikleri manuel olarak birleştiririm.

git difftoll <branch-1>..<branch-2>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.