Git rebase --onto'nun davranışını anlayamıyorum


169

Aşağıdaki git komutlarının iki bloğunun farklı davranışları olduğunu fark ettim ve nedenini anlamıyorum.

Biriyle ayrılan bir Ave bir Bşubem varcommit

---COMMIT--- (A)
\
 --- (B)

BEn son şubeyi yeniden oluşturmak istiyorum A(ve Bşubeye bağlı kalmak istiyorum)

---COMMIT--- (A)
         \
          --- (B)

Yaparsam sorun değil:

checkout B
rebase A

Ama eğer yaparsam:

checkout B
rebase --onto B A

Hiç işe yaramıyor, hiçbir şey olmuyor. İki davranışın neden farklı olduğunu anlamıyorum.

Phpstorm git istemcisi ikinci sözdizimini kullanır ve bu yüzden bana tamamen kırık gibi geliyor, bu yüzden bu sözdizimi sorununu soruyorum.


Yanıtlar:


412

tl; Dr.

Doğru sözdizimi rebase Büstünde Akullanarak git rebase --ontosenin durumunda:

git checkout B
git rebase --onto A B^

veya referans verilen veya öğesinin üst öğesi olan taahhütten başlayarak yeniden tabanına BalınAB .B^B~1

git rebase <branch>Ve arasındaki farkla ilgileniyorsanız git rebase --onto <branch>.

Hızlı: git rebase

git rebase <branch>tarafından başvurulan şu anda teslim aldığınız dalı, rebase gidiyor HEADüstüne, son o ulaşılabilir taahhüt gelen <branch>ama değil gelen HEAD.
Bu en yaygın yeniden bastırma ve tartışmalı olarak daha az planlama gerektiren durumdur.

          Before                           After
    A---B---C---F---G (branch)        A---B---C---F---G (branch)
             \                                         \
              D---E (HEAD)                              D---E (HEAD)

Bu örnekte Fve Gbunlardan ulaşılabilen, branchancak erişilemeyen taahhütlerdir HEAD. Diyor git rebase branchalacak Dilk dallanma noktasından sonra işlemek olduğunu, ve bunu rebase (yani onun üst değiştirmek erişilebilir en güncel öğelerden) kesinleştirme branchancak gelen HEADolduğunu, G.

Kesinlik: git rebase --onto 2 argümanla

git rebase --ontobelirli bir işlemden başlayarak yeniden oluşturmanıza olanak tanır . Neye ve nerede yeniden temellendirildiğini tam olarak kontrol etmenizi sağlar. Bu, kesin olmanız gereken senaryolar içindir.

Örneğin, baştan başlayarak HEADtam olarak yeniden temellendirmemiz gerektiğini düşünelim . Sadece çalışma kolumuzu getirmekle ilgileniyoruz , aynı zamanda tutmak istemiyoruz çünkü uyumsuz değişiklikler içeriyor.FEFD

          Before                           After
    A---B---C---F---G (branch)        A---B---C---F---G (branch)
             \                                     \
              D---E---H---I (HEAD)                  E---H---I (HEAD)

Bu durumda söyleyebiliriz git rebase --onto F D. Bu şu anlama gelir:

HEADEbeveyninin Den üstte olduğu komuta ulaşılabilir F.

Başka bir deyişle, üst öğesini olarak Eolarak Ddeğiştirin F. Sözdizimi git rebase --ontoo zaman git rebase --onto <newparent> <oldparent>.

Bunun işe yaradığı bir başka senaryo, etkileşimli bir yeniden işlem yapmak zorunda kalmadan mevcut şubeden bazı taahhütleri hızlı bir şekilde kaldırmak istediğinizdir :

          Before                       After
    A---B---C---E---F (HEAD)        A---B---F (HEAD)

Bu örnekte, diziyi kaldırmak Cve Ediziden çıkarmak için söyleyebilir git rebase --onto B Eya da eski ebeveynin bulunduğu yerin HEADüzerine yeniden basabilirsiniz .BE

Cerrah: git rebase --onto 3 argümanla

git rebase --ontohassasiyet açısından bir adım daha ileri gidebilir. Aslında, rasgele bir dizi taahhüdü başka birinin üstünde yeniden oluşturmanıza izin verir .

İşte bir örnek:

          Before                                     After
    A---B---C---F---G (branch)                A---B---C---F---G (branch)
             \                                             \
              D---E---H---I (HEAD)                          E---H (HEAD)

Bu durumda, şu anda işaret ettiği yeri görmezden gelerek tam aralığı yeniden E---Holuşturmak istiyoruz . Bunu söyleyerek yapabiliriz , yani:FHEADgit rebase --onto F D H

Üst öğesi Den Hüstte olan taahhütlerin aralığını yeniden oluşturun F.

Sonra git rebase --ontobir dizi taahhüt ile sözdizimi olur git rebase --onto <newparent> <oldparent> <until>. Hüner burada tarafından başvurulan kesinleştirme olduğunu hatırlıyor <until>edilir dahil aralığında ve yeni olacak HEADRebase tamamlandıktan sonra.


1
Güzel cevap. Genel durum için sadece küçük bir ek: <oldparent>Aralığın iki kısmı farklı dallarda ise ad bozulur. Genellikle: "Ulaşılabilen her taahhüdü dahil edin, <until>ancak ulaşılabilen her taahhüdü hariç tutun <oldparent>."
musiKk

50
git rebase --onto <newparent> <oldparent>gördüğüm en iyi -onto davranış açıklamasıdır!
ronkot

4
Teşekkürler! Ben --ontoseçenek ile biraz mücadele oldu ama bu kristal berraklığında yaptı! Ben daha önce anlayamadım bile bunu anlamıyorum: D Mükemmel "öğretici" için teşekkürler :-)
grongor

3
Bu cevap mükemmel olsa da, olası tüm durumları kapsamadığını hissediyorum. Son sözdizimi formu, daha süptil bir rebase tipini ifade etmek için de kullanılabilir. Pro Git (2. Baskı) örneğinde yer alan D'nin H'nin atası olması gerekmez. Bunun yerine, D ve H ortak bir ata ile de taahhüt edilebilir - bu durumda Git ortak atalarını anlar ve bu atadan H'ye F üzerine tekrar oynat
Pastafarian

1
Bu yardımcı oldu. Man sayfası argümanları hiç açıklamıyor.
a544jh

61

Anlamak için bilmeniz gereken her şey bu --onto:

git rebase --onto <newparent> <oldparent>

Bir ebeveyni bir taahhütte değiştiriyorsunuz, ancak taahhüdün gölgesini değil, sadece şimdiki (eski) ebeveynin gölgesini sağlıyorsunuz.


4
Kısa ve kolay. Aslında, bu taahhüt yerine yeniden pazarlamak istediğim kişinin ebeveyn taahhüdünü sağlamak zorunda olduğumun farkına varmak beni en uzun sürdü.
Antoniossss

1
Önemli bir ayrıntı, yaşlı bir şubenin çocuğunu mevcut şubeden seçmenizdir, çünkü bir taahhüt birçok taahhüdün ebeveyni olabilir, ancak kendinizi mevcut şubeyle sınırladığınızda, taahhüt sadece bir taahhüt için ebeveyn olabilir. Başka bir deyişle, ana ilişki gemisi dalda benzersizdir ancak dal belirtmezseniz olması gerekmez.
Trismegistos

2
Not: Şube içinde olmanız veya şube adını 3. parametre olarak git rebase --on <newparent> <oldparent> <feature-branch> olarak eklemeniz gerekir
Jason Portnoy

1
Bu cevap şaşırtıcı, doğrudan bu iş parçacığında gerektiği noktaya
John Culviner

13

Kısaca belirtmek gerekirse:

      Before rebase                             After rebase
A---B---C---F---G (branch)                A---B---C---F---G (branch)
         \                                         \   \
          D---E---H---I (HEAD)                      \   E'---H' (HEAD)
                                                     \
                                                      D---E---H---I

git rebase --onto F D H

Hangisi ile aynı (çünkü --ontobir argüman alır):

git rebase D H --onto F

Rebase, F'nin üstündeki aralık (D, H) olarak çalışır, aralığın soldan özel olduğuna dikkat edin.Özeldir çünkü örn.branch izin gitdan taahhüt ayrıldığı 1st bulmak branchyani Dhangi potansiyel H.

OP davası

    o---o (A)
     \
      o (B)(HEAD)

git checkout B
git rebase --onto B A

Tek komutla değiştirilebilir:

git rebase --onto B A B

Burada hataya benzeyen şey, yerleşimin B" Büstte şubeye yol açan bazı taahhütleri taşı" anlamına gelir B. Sorular "bazı taahhütlerin" ne olduğudur. Eğer eklerseniz -ibayrağı bunu tarafından işaret kesinleştirme bekar göreceksinizHEAD . Taahhüt atlanır, çünkü zaten --ontohedefe uygulanır Bve böylece hiçbir şey olmaz.

Şube adının bu şekilde tekrarlandığı her durumda komut saçmadır. Bunun nedeni, taahhütlerin aralığının o dalda bulunan bazı taahhütler olması ve rebase sırasında hepsinin atlanmasıdır.

Daha fazla açıklama ve uygulanabilir kullanımı git rebase <upstream> <branch> --onto <newbase>.

git rebase varsayılan.

git rebase master

Şunlardan birine genişler:

git rebase --onto master master HEAD
git rebase --onto master master current_branch

Rebase'den sonra otomatik ödeme.

Standart şekilde kullanıldığında, örneğin:

git checkout branch
git rebase master

Rebase en son yeniden temelli taahhüdüne geçtikten ve gitgeçtiğini fark etmeyeceksiniz ( geçmişe bakın ). 2. argüman taahhüt karma olduğunda ilginç olan nedirbranchgit checkout branchgit reflog bunun yerine şube adı rebase hala çalışır, ancak hareket ettirilecek bir şube yoktur, böylece taşınan şubeye teslim olmak yerine "müstakil HEAD" ile sonuçlanırsınız.

Birincil ayrıştırılmış taahhütleri atlayın.

masterİçinde --onto1 alınır git rebaseargüman.

                   git rebase master
                              /    \
         git rebase --onto master master

Bu yüzden pratik olarak başka herhangi bir taahhüt veya şube olabilir. Bu şekilde, en son olanları alarak ve birincil ayrıştırılmış taahhütleri bırakarak rebase taahhütlerinin sayısını sınırlandırabilirsiniz.

git rebase --onto master HEAD~
git rebase --onto master HEAD~ HEAD  # Expanded.

Tek tarafından sivri işlemek rebase Will HEADiçin masterve "müstakil HEAD" sonuna kadar.

Açık kontrollerden kaçının.

Varsayılan HEADveya current_branchargüman bağlamsal olarak bulunduğunuz yerden alınır. Bu yüzden çoğu insan yeniden temellendirmek istedikleri şubeye ödeme yapar. Ancak 2. rebase argümanı açıkça verildiğinde, rebase'i örtük bir şekilde iletmek için önce ödeme yapmanız gerekmez.

(branch) $ git rebase master
(branch) $ git rebase master branch  # Expanded.
(branch) $ git rebase master $(git rev-parse --abbrev-ref HEAD)  # Kind of what git does.

Bu, taahhütleri ve şubeleri herhangi bir yerden yeniden oluşturabileceğiniz anlamına gelir . Yani rebase sonra otomatik ödeme ile birlikte . Rebase temelli şubeyi yeniden oluşturmadan önce veya sonra ayrı ayrı kontrol etmeniz gerekmez.

(master) $ git rebase master branch
(branch) $ # Rebased. Notice checkout.

8

Basitçe söylemek gerekirse, git rebase --ontobir dizi taahhüdü seçer ve parametre olarak verilen taahhüde dayanır.

Adam sayfalarını okuyun, git rebase"üzerine" arayın. Örnekler çok iyi:

example of --onto option is to rebase part of a branch. If we have the following situation:

                                   H---I---J topicB
                                  /
                         E---F---G  topicA
                        /
           A---B---C---D  master

   then the command

       git rebase --onto master topicA topicB

   would result in:

                        H'--I'--J'  topicB
                       /
                       | E---F---G  topicA
                       |/
           A---B---C---D  master

Bu durumda size gelen kaydedilmesini rebase git söyle topicAiçin topicBüstünde master.


8

Daha iyi için arasındaki farkı anlamak git rebaseve git rebase --ontoher iki komutlar için olası davranışları ne olduğunu bilmek iyidir. git rebasetaahhütlerimizi seçilen dalın üstüne taşımamıza izin verin. Burası gibi:

git rebase master

ve sonuç:

Before                              After
A---B---C---F---G (master)          A---B---C---F---G (master)
         \                                           \
          D---E (HEAD next-feature)                   D'---E' (HEAD next-feature)

git rebase --ontodaha doğrudur. Nereden başlamak istediğimizi ve nerede bitirmek istediğimizi belirleyebilmemizi sağlıyor. Burası gibi:

git rebase --onto F D

ve sonuç:

Before                                    After
A---B---C---F---G (branch)                A---B---C---F---G (branch)
         \                                             \
          D---E---H---I (HEAD my-branch)                E'---H'---I' (HEAD my-branch)

Daha fazla bilgi almak için git rebase hakkında kendi makalemi incelemenizi tavsiye ederim - genel bakış


@Makyen Tabii, bunu aklımda tutacağım :)
womanonrails

Yani, biz okuyabilir git rebase --onto F Dolarak F gibi D'nin ebeveynin seti çocuk yapamayız?
Prihex

2

Çünkü ontoiki ek şubeye ihtiyacınız var. Bu komutla , başka bir şubeye branchBdayanan taahhütleri uygulayabilirsiniz branchAörn master. Aşağıdaki örnekte branchBdayanmaktadır branchAve değişiklikleri uygulamak istediğiniz branchBüzerinde masterdeğişiklikleri uygulamadan branchA.

o---o (master)
     \
      o---o---o---o (branchA)
                   \
                    o---o (branchB)

komutları kullanarak:

checkout branchB
rebase --onto master branchA 

taahhüt hiyerarşisini takip edersiniz.

      o'---o' (branchB)
     /
o---o (master)
     \
      o---o---o---o (branchA)

1
Biraz daha açıklayabilir misiniz, eğer ustaya yeniden soymak istiyorsak, nasıl olur da mevcut şube haline gelir? Bunu yaparsanız rebase --onto branchA branchB, tüm ana dalı şubeA'nın başına mı koyacaksınız?
Polymerase

8
bu olmamalı checkout branchB: rebase --onto master branchAmı?
goldenratio

4
Bu neden iptal edildi? bu söylediği şeyi yapmaz.
De Novo

Cevabı düzenledim ve düzelttim, bu yüzden insanlar ilk önce repo dallarını kırmak zorunda değiller ve hemen sonra gelip yorumları okuyun ... 🙄
Kamafeather

0

git rebase --ontoKavramanın zor olduğu başka bir durum daha var : simetrik bir fark seçiciden (üç nokta ' ...') sonuçlanan bir taahhüde geri döndüğünüzde

Git 2.24 (4. Çeyrek 2019) bu vakayı yönetmek için daha iyi bir iş çıkarıyor:

Bkz 414d924 işlemek , 4effc5b işlemek , c0efb4c işlemek , 2b318aa taahhüt (27 Ağustos 2019), ve 793ac7e taahhüt , 359eceb taahhüt tarafından (25 Ağustos 2019) Denton Liu ( Denton-L) . Yardımcı
: Eric Sunshine ( sunshineco) , Junio ​​C Hamano ( gitster) , Ævar Arnfjörð Bjarmason ( avar) ve Johannes Schindelin ( dscho) .
Bkz. Taahhüt 6330209 , taahhüt c9efc21 (27 Ağu 2019) ve taahhüt 4336d36 (25 Ağu 2019) Ævar Arnfjörð Bjarmason (avar ).
Yardımcı : Eric Sunshine ( sunshineco) , Junio ​​C Hamano ( gitster) , Ævar Arnfjörð Bjarmason ( avar) ve Johannes Schindelin ( dscho) .
(Göre Birleştirilmiş - Junio Cı Hamano gitster- içinde 640f9cd tamamlama 2019 30 Eki)

rebase: --ontodaha fazla durumda hızlı ileri sarma

Daha önce, aşağıdaki grafiğe sahip olduğumuzda,

A---B---C (master)
     \
      D (side)

koşmak ' git rebase --onto master... master side' Dne olursa olsun her zaman yeniden temellendirilir.

Bu noktada, Git diff kesinleştirme aralıklarında " Çift nokta ' ..' ve üçlü nokta arasındaki farklar nelerdir ...? "

https://sphinx.mythic-beasts.com/~mark/git-diff-help.png

İşte: " master..." atıfta master...HEADolan B: BAŞ yan BAŞ (henüz kontrol): Eğer üzerine rebasing edilmektedir B.
Neye dayanıyorsun? Herhangi işlemek değil master'da ve erişilebilir sidedalı: tek bu tarife uyan kesinleştirme var D... üstünde zaten B!

Yine, Git 2.24'ten önce, böyle bir rebase --ontodurum Dne olursa olsun her zaman yeniden basmaya neden olur.

Bununla birlikte, istenen davranış, rebase'in bunun hızlı bir şekilde önlenebilir olduğunu fark etmesi ve bunun yerine bunu yapmasıdır .

rebase --onto B AHiçbir şey yapmayan OP'ye benziyor .

can_fast_forwardBu vakanın algılanabilmesi ve bir ileri sarma gerçekleştirilmesi için algılama ekleyin .
Her şeyden önce, mantığı basitleştiren goto'ları kullanmak için işlevi yeniden yazın.
Sonra,

options.upstream &&
!oidcmp(&options.upstream->object.oid, &options.onto->object.oid)

koşullar kaldırıldı cmd_rebase, biz yerine bir yeniden can_fast_forward.
Özellikle, birleştirme tabanlarının kontrol edilmesi upstreamve headiçindeki başarısız bir durumu düzeltir t3416.

T3416 için kısaltılmış grafik aşağıdaki gibidir:

        F---G topic
       /
  A---B---C---D---E master

ve başarısız olan komut

git rebase --onto master...topic F topic

Daha önce Git, bir birleştirme tabanı ( C, sonucu master...topic) olduğunu ve birleştirme ve üstünün aynı olduğunu görecekti, bu yüzden hızlı bir şekilde ileriye gidebileceğimizi gösteren yanlış 1 döndürecekti. Bu, yeniden temel alınan grafiğin ` ABCFG` beklediğimizde ' ABCG' olmasına neden olur .

Bir rebase --onto C F topicaracı işlemeye sonra F ulaşılabilir, topic: baştaki Gdeğil, sadece Fkendisi.
Bu durumda hızlı yönlendirme F, yanlış olan yeniden temelli dalı da içerecektir .

Ek mantıkla, yukarı ve başın birleştirme tabanının olduğunu tespit ederiz F. Üzerine olmadığından F, biz gelen kaydedilmesini tam set rebasing değil demektir master..topic.
Bazı kaydedilmesini hariç yaptığınızdan, ileri sarma olamaz yapılması ve doğru olarak 0 dönmek böylece.

-fBu değişikliğin bir sonucu olarak başarısız olan vakaları test etmek için ekleyin , çünkü bir geri göndermenin zorlanması için bir hızlı ileri beklemiyorlardı.

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.