Kiraz bir dizi taahhüdü nasıl seçer ve başka bir dalda birleştirilir?


640

Aşağıdaki depo düzenim var:

  • ana şube (üretim)
  • bütünleşme
  • Çalışma

Ulaşmak istediğim şey, çalışma dalından bir dizi taahhüt almak ve onu entegrasyon dalına birleştirmektir. Gitmek için oldukça yeni ve depoyu bozmadan tam olarak nasıl yapılacağını anlayamıyorum (birleştirmeyi değil bir işlemde taahhüt aralıklarının kiraz toplama). Bu konuda herhangi bir işaret veya düşünce? Teşekkürler!


Yanıtlar:


808

Bir dizi iş söz konusu olduğunda, kiraz toplama dır-dir oldu pratik değil.

Gibi aşağıda belirtilen tarafından Keith Kim , Git 1.7.2+ kaydedilmesini bir dizi-seçmenin kiraz yeteneğini tanıtıldı (ama yine de farkında olmak gerekir gelecekteki birleştirme amaçlı toplama kiraz sonucu )

git cherry-pick "bir dizi taahhüt seçmeyi öğrendi
(örn." cherry-pick A..B"ve" cherry-pick --stdin")," git revert"yaptı; bunlar daha güzel sıralama kontrolünü desteklemiyor" rebase [-i]"da var.

damian yorum yapar ve bizi uyarır:

" cherry-pick A..B" AŞeklinde daha büyük olmalıdırB .
Eğer yanlış sıralarsa, komut sessizce başarısız olur .

Eğer almak istiyorsanız aralığı Bboyunca D(dahil) olurdu B^..D. Örnek olarak
" Git önceki taahhütler aralığından şube oluştursun mu? "

As Jubobs bahseder yorumlarda :

Bu Bbir kök taahhüdü olmadığını varsayar ; unknown revisionaksi takdirde " " hatası alırsınız .

Not: Git itibariyle 2.9.x / 2.10 (Q3 2016), yetim dalı (boş kafa) doğrudan taahhüt bir dizi kiraz-seçebilirsiniz: bkz " Nasıl GIT'de mevcut şube yetim yapmak ".


Orijinal cevap (Ocak 2010)

A rebase --onto, daha iyi olurdu, burada Charles Bailey'nin burada açıkladığı gibi, entegrasyon dalınızın üstünde verilen taahhüdü tekrar oynatırsınız .
(ayrıca, pratik bir örnek görmek için git rebase man sayfasında "Bir şubeye dayalı bir konu dalını nasıl başka bir yere nakletirsiniz " konusuna bakın git rebase --onto)

Mevcut dalınız entegrasyonsa:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration

Bu, aşağıdakiler arasındaki her şeyi yeniden oynatır:

  • öğesinin üst öğesinden sonra first_SHA-1_of_working_branch_range(dolayısıyla ~1): yeniden yürütmek istediğiniz ilk işlem
  • " integration" e kadar ( workingşubeden tekrar oynatmak istediğiniz son işleme işaret eder )

" tmp" (daha integrationönce nereye işaret ettiğini gösteren)

Bu taahhütlerden biri tekrar oynatıldığında herhangi bir çakışma olursa:

  • ya çöz ve " git rebase --continue" komutunu çalıştır .
  • veya bu yamayı atlayın ve " git rebase --skip" çalıştırın
  • veya her şeyi " git rebase --abort" ile iptal edin (ve integrationdalı şubeye geri koyun tmp)

Bundan sonra rebase --onto, integrationgeri sonunda olacak ( "olduğu entegrasyon şube taahhüt tmp" dalı + tüm tekrarlattırılır kaydedilmesini)

Kiraz toplamada veya rebase --ontounutma, burada tarif edildiği gibi sonraki birleşmelerde sonuçları vardır .


Saf bir " cherry-pick" çözüm burada tartışılır ve şöyle bir şey içerir:

Bir yama yaklaşımı kullanmak istiyorsanız, "git format-patch | git am" ve "git cherry" seçeneklerinizdir.
Şu anda, git cherry-picktaahhüt yalnızca tek kabul eder ancak aralığı belirleyip istiyorsanız Baracılığıyla Dolurdu B^..Dgit tabir de, bu yüzden

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 

Her neyse, bir dizi taahhüdü "tekrar oynamanız" gerektiğinde, "tekrar" kelimesi sizi rebaseGit'in " " özelliğini kullanmaya itmelidir.


1
-mSeçeneği gerektiren ebeveynleri olan taahhütleriniz varsa , bu taahhütleri nasıl ele alırsınız? Yoksa bu taahhütleri filtrelemenin bir yolu var mı?
Ağustos

@aug'un bu kiraz toplama için seçtiğiniz parametre -mtarafından referans verilen ana hattı seçerek bunları sizin için halletmesi gerekiyor -m.
VonC

Mesele şu ki, kiraz bir dizi taahhüt seçiyorsanız, kiraz ebeveynin taahhütlerini doğru bir şekilde seçecektir, ancak normal bir taahhüdüne çarptığında başarısız olur ve taahhüdün bir birleşme olmadığını söyler. Sanırım sorum daha iyi nasıl -msadece kiraz toplama aralığı taahhütleri bir üst taahhüt vurur seçeneği geçmek nasıl ifade edilir ? Şu anda geçirirseniz -mgibi git cherry-pick a87afaaf..asfa789 -m 1aralık dahilindeki tüm kaydedilmesini için geçerlidir.
Ağustos

@aug Garip, sorunu tekrarlamadım. Git sürümünüz nedir ve tam olarak gördüğünüz hata mesajı nedir?
VonC

Ah git sürüm 2.6.4'ü (Apple Git-63) çalıştırıyorum. Gördüğüm hata, error: Commit 8fcaf3b61823c14674c841ea88c6067dfda3af48 is a merge but no -m option was given.aslında yapabileceğinizi fark ettiğim gibi bir şey olurdu git cherry-pick --continueve iyi olurdu (ancak ebeveyn taahhüdünü içermez)
Ağustos

136

Git v1.7.2 kiraz toplama bir dizi taahhüdü kabul edebilir:

git cherry-pickbir dizi taahhüt seçmeyi öğrendi (ör. cherry-pick A..Bve cherry-pick --stdin) git revert; bunlar rebase [-i]olsa da güzel sıralama kontrolü desteklemiyor .


103
cherry-pick A..BA taahhüdü almayacağınızı unutmayın (buna ihtiyacınız A~1..Bolacak) ve herhangi bir çatışma varsa git rebase gibi otomatik olarak devam etmeyecektir (en az
1.7.3.1'den itibaren

3
git cherry-pick A..B CSaf olarak beklediğiniz gibi çalışmadığını da unutmayın . Aralıktaki her şeyi seçmeyecek A..Bve taahhütte bulunmayacak C! Bunu yapmak için, önce git cherry-pick A..Bve sonra iki satıra bölmeniz gerekir git cherry-pick C. Bu nedenle, bir aralığınız olduğunda, ayrı olarak yürütmeniz gerekir.
MicroVirus

42

2 şubeniz olduğunu varsayalım,

"branchA": kopyalamak istediğiniz taahhütleri içerir ("commitA" dan "commitB" e

"branchB": taahhütlerin "branchA" dan aktarılmasını istediğiniz dal

1)

 git checkout <branchA>

2) "commitA" ve "commitB" kimliklerini alın

3)

git checkout <branchB>

4)

git cherry-pick <commitA>^..<commitB>

5) Bir çakışma olması durumunda, onu çözün ve yazın

git cherry-pick --continue

kiraz toplama işlemine devam etmek.


Cazibe gibi çalıştı! Çok teşekkürler!
snukone

28

Dalları gerçekten birleştirmek istemediğinizden emin misiniz? Çalışan dalda istemediğiniz bazı taahhütler varsa, istediğiniz noktada HEAD ile yeni bir dal oluşturabilirsiniz.

Şimdi, bir dizi taahhüdü gerçekten seçmek istiyorsanız, ne olursa olsun, bunu yapmanın zarif bir yolu sadece bir yama setini çekmek ve yeni entegrasyon şubenize uygulamaktır:

git format-patch A..B
git checkout integration
git am *.patch

Bu git-rebase'in zaten yaptığı şey, ama oyun oynamaya gerek kalmadan. Ekleyebilir --3wayiçin git-amBirleştirmek gerekiyorsa. Talimatları aynen uygularsanız, dizinde zaten başka bir * .patch dosyası olmadığından emin olun ...


1
Diğer revizyon aralıklarında olduğu gibi A^, dahil edilmesi gerektiğini unutmayın A.
Gino Mempin

9

Ben sarılmış VonC kodunu , kısa bash komut dosyası içine git-multi-cherry-pickkolay çalışması için,:

#!/bin/bash

if [ -z $1 ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:  $0 start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order $1 | while read rev 
do 
  git cherry-pick $rev || break 
done 

Şu anda bunu hem 3. taraf kodu hem de özelleştirmeleri aynı svn bagajında ​​karışık olan bir projenin geçmişini yeniden oluştururken kullanıyorum. Şimdi, ilerideki özelleştirmeleri daha iyi anlamak için çekirdek 3. taraf kodunu, 3. taraf modüllerini ve özelleştirmeleri kendi git dallarına ayırıyorum. git-cherry-pickaynı depoda, ancak ortak bir ata olmadan iki ağacım olduğu için bu durumda yardımcı olur.


3

Yukarıdaki tüm seçenekler birleştirme çakışmalarını çözmenizi ister. Bir takım için yapılan değişiklikleri birleştiriyorsanız, geliştiricilerin birleştirme çakışmalarını çözüp ilerlemek zordur. Ancak, "git merge" birleşmeyi tek seferde yapar, ancak argüman olarak bir dizi düzeltmeyi geçemezsiniz. devirlerin birleştirme aralığını yapmak için "git diff" ve "git uygula" komutlarını kullanmalıyız. Yama dosyası çok fazla dosya için fark varsa "git uygula" nın başarısız olacağını gözlemledim, bu yüzden dosya başına bir yama oluşturmak ve sonra uygulamak zorundayız. Komut dosyasının, kaynak dalda silinen dosyaları silemeyeceğini unutmayın. Bu nadir bir durumdur, bu tür dosyaları hedef şubeden elle silebilirsiniz. Düzeltme ekini uygulayamıyorsa, "git uygula" nın çıkış durumu sıfır değildir,

Komut dosyası aşağıdadır.

enter code here



  #!/bin/bash

    # This script will merge the diff between two git revisions to checked out branch
    # Make sure to cd to git source area and checkout the target branch
    # Make sure that checked out branch is clean run "git reset --hard HEAD"


    START=$1
    END=$2

    echo Start version: $START
    echo End version: $END

    mkdir -p ~/temp
    echo > /tmp/status
    #get files
    git --no-pager  diff  --name-only ${START}..${END} > ~/temp/files
    echo > ~/temp/error.log
    # merge every file
    for file in `cat  ~/temp/files`
    do
      git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
      if [ $? -ne 0 ]
      then
#      Diff usually fail if the file got deleted 
        echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
        echo Skipping the merge: git diff command failed for $file
        echo "STATUS: FAILED $file" >>  /tmp/status
        echo "STATUS: FAILED $file"
    # skip the merge for this file and continue the merge for others
        rm -f ~/temp/git-diff
        continue
      fi

      git apply  --ignore-space-change --ignore-whitespace  --3way --allow-binary-replacement ~/temp/git-diff

      if [ $? -ne 0 ]
       then
#  apply failed, but it will fall back to 3-way merge, you can ignore this failure
         echo "git apply command filed for $file"
       fi
       echo
       STATUS=`git status -s $file`


       if [ ! "$STATUS" ]
       then
#   status is null if the merged diffs are already present in the target file
         echo "STATUS:NOT_MERGED $file"
         echo "STATUS: NOT_MERGED $file$"  >>  /tmp/status
       else
#     3 way merge is successful
         echo STATUS: $STATUS
         echo "STATUS: $STATUS"  >>  /tmp/status
       fi
    done

    echo GIT merge failed for below listed files

    cat ~/temp/error.log

    echo "Git merge status per file is available in /tmp/status"

2

Bunu birkaç gün önce, Vonc'un çok net açıklamasını okuduktan sonra test ettim.

Adımlarım

Başlat

  • Şube dev: ABCDEFGHIJ
  • Şube target: ABCD
  • İstemiyorum Ene deH

Dalda E ve H adımı olmadan özellikleri kopyalama adımları dev_feature_wo_E_H

  • git checkout dev
  • git checkout -b dev_feature_wo_E_H
  • git rebase --interactive --rebase-merges --no-ff DRebase editörünün dropönüne Eve içine koydumH
  • çatışmaları çözmek, devam etmek ve commit

Şubeyi dev_feature_wo_E_Hhedefe kopyalama adımları .

  • git checkout target
  • git merge --no-ff --no-commit dev_feature_wo_E_H
  • çatışmaları çözmek, devam etmek ve commit

Bazı açıklamalar

  • Bunu cherry-pickönceki günlerde çok fazla olduğu için yaptım
  • git cherry-pick güçlü ve basit ama

    • yinelenen taahhütler oluşturur
    • ve mergeilk taahhütlerin ve yinelenen taahhütlerin çatışmalarını çözmek istediğimde , bir veya iki cherry-pickiçin "kiraz toplama" sorun değil, ama daha fazlası için çok ayrıntılı ve şube çok karmaşık olacak
  • Aklımda yaptığım adımlar, git rebase --onto

1
İyi yazı. Upvoted. Bana stackoverflow.com/a/38418941/6309 adresini hatırlatıyor . 2012'de kiraz toplamanın dezavantajlarını tekrar özetledim: stackoverflow.com/a/13524494/6309 .
VonC

1

Başka bir seçenek de stratejimizi bizimkilerle aralıktan önceki taahhüde birleştirmek ve daha sonra bu aralığın son taahhüdüyle (veya sonuncusu olduğunda dal) 'normal' birleştirme olabilir. Özellik dalında birleştirilecek yalnızca 2345 ve 3456 ana taahhütlerini varsayalım:

usta:
1234
2345
3456
4567

özellik dalında:

git birleştirme-bizimki 4567
git birleştirme 2345
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.