Git'in “rebase --preserve-merges” tam olarak ne yapar (ve neden?)


355

Git'in komutla ilgili belgelerirebase oldukça kısa:

--preserve-merges
    Instead of ignoring merges, try to recreate them.

This uses the --interactive machinery internally, but combining it
with the --interactive option explicitly is generally not a good idea
unless you know what you are doing (see BUGS below).

Peki kullandığınızda aslında ne olur --preserve-merges? Varsayılan davranıştan farkı nedir (bu bayrak olmadan)? Bir birleşmeyi "yeniden oluşturmak" ne anlama gelir?


20
Uyarı: Git 2.18'den (5 yıl sonra 2.Çeyrek) başlayarak git --rebase-mergeseski olanın yerini alacak git --preserve-merges. Aşağıdaki cevabımı
VonC

Yanıtlar:


464

Normal bir git rebaseinde olduğu gibi, git with --preserve-mergesilk olarak taahhüt grafiğinin bir bölümünde yapılan taahhütlerin bir listesini tanımlar ve daha sonra bu taahhütleri başka bir bölümün üstüne tekrar oynatır. --preserve-mergesKaygı ile ilgili farklılıklar tekrar için seçilir ve yeniden oynatmanın birleştirme taahhütlerinde nasıl çalıştığı.

Normal ve birleştirme koruyucu rebase arasındaki temel farklar hakkında daha açık olmak için:

  • Birleştirme koruyan rebase (bazı) birleştirme işlemlerini yeniden yürütmeye istekliyken, normal rebase birleştirme işlemlerini tamamen yok sayar.
  • Birleştirme taahhütlerini yeniden oynatmaya istekli olduğu için, birleştirme koruma rebase bir birleştirme taahhüdünü yeniden oynatmanın ne anlama geldiğini tanımlamalı ve bazı ekstra kırışıklıklar ile uğraşmalıdır.
    • En ilginç kısım, kavramsal olarak, belki de yeni taahhüdün birleştirme ebeveynlerinin ne olması gerektiğini seçmektir.
    • Birleştirme işlemlerinin yeniden yürütülmesi ayrıca belirli taahhütlerin ( git checkout <desired first parent>) açıkça kontrol edilmesini gerektirir , oysa normal rebase bunun için endişelenmesine gerek yoktur.
  • Birleştirmeyi koruyan rebase, yeniden oynatma için daha sığ bir dizi işi dikkate alır:
    • Özellikle, yalnızca en son birleştirme üslerinden (yani son iki dalın ayrıştığından beri) yapılan taahhütlerin tekrarını dikkate alırken, normal yeniden taban iki dalın ilk kez ayrıldığı taahhütleri tekrarlayabilir .
    • Geçici ve belirsiz olmak için, bunun nihayetinde birleştirme taahhüdüne "dahil edilmiş olan" eski taahhütleri "tekrar etmenin bir yolu olduğuna inanıyorum.

İlk önce, rebase'in ne yaptığını "yeterince tam olarak" anlatmaya çalışacağım --preserve-mergesve sonra bazı örnekler vereceğim. Daha faydalı görünüyorsa, elbette örnekler ile başlanabilir.

"Kısa" da Algoritma

Yabancı otlara gerçekten girmek istiyorsanız, git kaynağını indirin ve dosyayı keşfedin git-rebase--interactive.sh. (Rebase, Git'in C çekirdeğinin bir parçası değildir, aksine bash ile yazılır. Ve perde arkasında "interaktif rebase" ile kod paylaşır.)

Ama burada bunun özü olduğunu düşündüğüm çizimi çizeceğim. Düşünülecek şey sayısını azaltmak için birkaç özgürlük aldım. (örneğin, hesaplamaların yapıldığı kesin sırayı% 100 doğrulukla yakalamaya çalışmıyorum ve daha az merkezi görünen bazı konuları görmezden gelmiyorum, örneğin şubeler arasında önceden seçilmiş komisyonlar hakkında ne yapacağım).

İlk olarak, birleştirme korumalı olmayan bir tabanın oldukça basit olduğunu unutmayın. Az ya da çok:

Find all commits on B but not on A ("git log A..B")
Reset B to A ("git reset --hard A") 
Replay all those commits onto B one at a time in order.

Rebase --preserve-mergesnispeten karmaşıktır. İşte oldukça önemli görünen şeyleri kaybetmeden yapabildiğim kadar basit:

Find the commits to replay:
  First find the merge-base(s) of A and B (i.e. the most recent common ancestor(s))
    This (these) merge base(s) will serve as a root/boundary for the rebase.
    In particular, we'll take its (their) descendants and replay them on top of new parents
  Now we can define C, the set of commits to replay. In particular, it's those commits:
    1) reachable from B but not A (as in a normal rebase), and ALSO
    2) descendants of the merge base(s)
  If we ignore cherry-picks and other cleverness preserve-merges does, it's more or less:
    git log A..B --not $(git merge-base --all A B)
Replay the commits:
  Create a branch B_new, on which to replay our commits.
  Switch to B_new (i.e. "git checkout B_new")
  Proceeding parents-before-children (--topo-order), replay each commit c in C on top of B_new:
    If it's a non-merge commit, cherry-pick as usual (i.e. "git cherry-pick c")
    Otherwise it's a merge commit, and we'll construct an "equivalent" merge commit c':
      To create a merge commit, its parents must exist and we must know what they are.
      So first, figure out which parents to use for c', by reference to the parents of c:
        For each parent p_i in parents_of(c):
          If p_i is one of the merge bases mentioned above:
            # p_i is one of the "boundary commits" that we no longer want to use as parents
            For the new commit's ith parent (p_i'), use the HEAD of B_new.
          Else if p_i is one of the commits being rewritten (i.e. if p_i is in R):
            # Note: Because we're moving parents-before-children, a rewritten version
            # of p_i must already exist. So reuse it:
            For the new commit's ith parent (p_i'), use the rewritten version of p_i.
          Otherwise:
            # p_i is one of the commits that's *not* slated for rewrite. So don't rewrite it
            For the new commit's ith parent (p_i'), use p_i, i.e. the old commit's ith parent.
      Second, actually create the new commit c':
        Go to p_1'. (i.e. "git checkout p_1'", p_1' being the "first parent" we want for our new commit)
        Merge in the other parent(s):
          For a typical two-parent merge, it's just "git merge p_2'".
          For an octopus merge, it's "git merge p_2' p_3' p_4' ...".
        Switch (i.e. "git reset") B_new to the current commit (i.e. HEAD), if it's not already there
  Change the label B to apply to this new branch, rather than the old one. (i.e. "git reset --hard B")

--onto CTartışmalı bir temele çok benzer olmalıdır. B'nin HEAD'ında kesin yürütmeyi başlatmak yerine, C'nin HEAD'ında kesin yürütmeyi başlatın. (Ve B_new yerine C_new kullanın.)

örnek 1

Örneğin, taahhüt grafiği alın

  B---C <-- master
 /                     
A-------D------E----m----H <-- topic
         \         /
          F-------G

m, E ve G ebeveynleriyle birleştirme taahhüdüdür.

Diyelim ki konuyu (H) masterın (C) üstüne, normal, birleştirme korumalı olmayan yeniden taban kullanarak yeniden oluşturduk. (Örneğin, ödeme konusu; rebase master .) Bu durumda, git yeniden oynatma için aşağıdaki işlemleri seçer:

  • D seç
  • E seç
  • F seç
  • G seç
  • H seç

ve sonra kesinleştirme grafiğini şu şekilde güncelleyin:

  B---C <-- master
 /     \                
A       D'---E'---F'---G'---H' <-- topic

(D ', D'nin vb. Tekrarlanan eşdeğeridir.)

Tekrarlama için birleştirme taahhüdü m'nin seçilmediğine dikkat edin.

Bunun yerine --preserve-mergesC'nin üstünde bir H teması yaptıysak (Örneğin, ödeme konusu; rebase --preserve-merges master .) Bu yeni durumda git, yeniden oynatma için aşağıdaki taahhütleri seçer:

  • D seç
  • E seç
  • F'yi seçin ('subtopic' dalında D'ye)
  • G'yi seçin ('subtopic' dalında F'ye)
  • 'subtopic' dalını konuya birleştir
  • H seç

Şimdi m edildi çalınması için seçilen. Ayrıca, E ve G birleştirme ebeveynlerinin, m birleştirme işleminden önce dahil edilmek üzere seçildiğine dikkat edin.

Sonuçta ortaya çıkan tamamlama grafiği:

 B---C <-- master
/     \                
A      D'-----E'----m'----H' <-- topic
        \          / 
         F'-------G'

Yine, D ', D'nin kiraz tarafından seçilmiş (yani yeniden oluşturulmuş) bir versiyonudur. E', vb. İçin aynıdır. Master'da olmayan her taahhüt tekrar oynatılmıştır. Hem E hem de G (m'nin birleşik ebeveynleri) m 'nin ebeveynleri olarak hizmet etmek için E' ve G 'olarak yeniden yaratılmıştır (rebase'den sonra ağaç geçmişi hala aynı kalır).

ÖRNEK 2

Normal rebase'den farklı olarak, birleştirme koruyucu rebase yukarı akış kafasında birden fazla çocuk oluşturabilir.

Örneğin:

  B---C <-- master
 /                     
A-------D------E---m----H <-- topic
 \                 |
  ------- F-----G--/ 

H'yi (konu) C (master) üzerine yeniden tabanlaştırırsak, rebase için seçilen taahhütler şunlardır:

  • D seç
  • E seç
  • F seç
  • G seç
  • m seç
  • H seç

Ve sonuç şöyle:

  B---C  <-- master
 /    | \                
A     |  D'----E'---m'----H' <-- topic
       \            |
         F'----G'---/

ÖRNEK 3

Yukarıdaki örneklerde, orijinal birleştirme işleminin sahip olduğu orijinal ebeveynlerden ziyade, hem birleştirme taahhüdü hem de iki ebeveyni yeniden yürütülür. Bununla birlikte, diğer bazlarda, tekrar birleştirme birleştirme taahhüdü, birleştirme işleminden önce zaten taahhüt grafiğinde olan ebeveynlerle sonuçlanabilir.

Örneğin:

  B--C---D <-- master
 /    \                
A---E--m------F <-- topic

Konuyu master'a yeniden birleştirirsek (birleştirmeleri koruyarak), yeniden oynatma taahhütleri

  • birleştirme taahhüdü seç
  • F seç

Yeniden yazılan tamamlama grafiği şöyle görünecektir:

                     B--C--D <-- master
                    /       \             
                   A-----E---m'--F'; <-- topic

Burada tekrarlanan birleştirme taahhüdü m ', tamamlama grafiğinde önceden var olan ebeveynleri, yani D (master'ın HEAD'i) ve E'yi (orijinal birleştirme taahhüdünün m ebeveynlerinden biri) alır.

Örnek 4

Birleştirme koruyan rebase, bazı "boş taahhüt" davalarında karışabilir. En azından bu sadece git'in bazı eski sürümleri için geçerlidir (örneğin 1.7.8.)

Bu taahhüt grafiğini alın:

                   A--------B-----C-----m2---D <-- master
                    \        \         /
                      E--- F--\--G----/
                            \  \
                             ---m1--H <--topic

Hem m1 hem de m2'nin B ve F'deki tüm değişiklikleri içermesi gerektiğini unutmayın.

git rebase --preserve-mergesH (konu) öğesini D (master) üzerine yapmaya çalışırsak , tekrar oynamak için aşağıdaki taahhütler seçilir:

  • m1 seç
  • H seç

M1'de birleştirilen değişikliklerin (B, F) zaten D'ye dahil edilmesi gerektiğini unutmayın. (Bu değişiklikler zaten m2'ye dahil edilmelidir, çünkü m2 B ve F'nin çocuklarını birleştirir.) Bu nedenle, kavramsal olarak, m1'i D muhtemelen ya bir işlem yapılmamalı ya da boş bir taahhüt oluşturmalıdır (yani ardışık revizyonlar arasındaki farkın boş olduğu bir işlem).

Ancak bunun yerine git, D'nin üstünde m1'i tekrar oynatma girişimini reddedebilir. Bunun gibi bir hata alabilirsiniz:

error: Commit 90caf85 is a merge but no -m option was given.
fatal: cherry-pick failed

Birinin git'e bir bayrak vermeyi unuttuğu anlaşılıyor, ancak altta yatan sorun git'in boş taahhütler oluşturmayı sevmemesidir.


6
Ben fark ettik git rebase --preserve-mergesolduğu çok yavaş bir daha rebaseolmadan --preserve-merges. Bu, doğru taahhütleri bulmanın bir yan etkisi mi? Hızlandırmak için yapabileceği bir şey var mı? (Bu arada… çok ayrıntılı cevap için teşekkürler!)
David Alan Hjelle

7
Her zaman --preserve-merges kullanmanız gerektiği gibi geliyor. Aksi takdirde tarihi kaybetme potansiyeli vardır, yani birleştirme taahhüt eder.
DarVar

19
@DarVar Rebase üzerinde her zaman geçmişi kaybedersiniz, çünkü gerçekte nerede olduğundan farklı bir kod tabanına yapılan yerlerde değişiklik olduğunu iddia edersiniz.
Chronial

5
Bu hala "geçici bir cevap" mı?
Andrew Grimm

5
@Chronial Tabii ki haklısınız, bu yeniden temellendirme her zaman kaybetme tarihini içeriyor, ancak belki DarVar sadece geçmişi kaybetmekle kalmayıp, aynı zamanda kod tabanında da değişiklik yapmayı kabul ediyordu. Çatışma çözümlemesi, bir geri ödeme yapılabilecek tüm olası yollarla kaybedilen bilgileri içerir. Her zaman yeniden yapmalısınız. Git'in çatışma çözümünüzü tekrar yapmasına izin vermenin gerçekten bir yolu yok mu? Git kiraz neden birleştirme taahhüdünü seçemiyor?
Nils_M

94

Git 2.18 (2. Çeyrek 2018) --preserve-mergeyeni bir seçenek ekleyerek seçeneği önemli ölçüde geliştirecektir .

Başka bir yerde taahhüt grafiğinin tüm topolojisini nakletmek için " git rebase" öğrenildi " --rebase-merges" .

(Not: Git 2.22, Q2 2019, aslında kullanımdan kaldırılıyor --preserve-merge ve Git 2.25, Q1 2020, " git rebase --help" çıktısında reklam vermeyi durduruyor )

Bkz 25cff9f işlemek , 7543f6f taahhüt , 1131ec9 taahhüt , 7ccdf65 taahhüt , 537e7d6 taahhüt , a9be29c işlemek , 8f6aed7 taahhüt , 1644c73 taahhüt , d1e8b01 işlemek , 4c68e7d işlemek , 9055e40 taahhüt , cb5206e işlemek , a01c2a5 işlemek , 2f6b1d1 taahhüt , bf5c057 taahhüt (2018 25 Apr) ile Johannes Schindelin ( dscho) .
Bakınız Stefan Beller ( ) tarafından f431d73 (25 Nis 2018 ) .stefanbeller
Bakınız Phillip Wood ( ) tarafından 2429335 (25 Nis 2018) taahhüdü . (Göre Birleştirilmiş Junio Cı Hamano - - içinde 2c18e6a tamamlama 2018 23 Mayıs)phillipwood
gitster

pull: --rebase-mergesşube topolojisini yeniden oluşturmayı kabul et

Seçeneği preserveyalnızca komuta ileten moda benzer şekilde, mod da --preserve-mergesseçeneği geçer .rebasemerges--rebase-merges

Bu, kullanıcıların yeni taahhütler çekerken düzleştirmeden önemsiz olmayan taahhüt topolojilerini rahatça yeniden tabanlaştırmasını sağlayacaktır.


git rebaseman sayfasında artık tarihin birleştirilmesiyle yeniden başlamaya ayrılmış tam bir bölüm var .

Ayıkla:

Bir geliştiricinin birleştirme taahhütlerini yeniden oluşturmak istemesinin meşru nedenleri vardır: birbiriyle ilişkili birden çok dal üzerinde çalışırken dal yapısını (veya "taahhüt topolojisi") tutmak.

Aşağıdaki örnekte, geliştirici, düğmelerin tanımlanma şeklini yeniden düzenleyen bir konu dalında ve "Hata bildir" düğmesini uygulamak için bu yeniden düzenleme işlemini kullanan başka bir konu dalında çalışır.
Çıkışı git log --graph --format=%s -5şöyle görünebilir:

*   Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one

Geliştirici master , örneğin ilk konu şubesinin masterikincisinden çok daha önce entegre edilmesi beklendiğinde , örneğin DownloadButtonsınıfta yapılan değişikliklerle birleştirme çakışmalarını çözmek için, bu taahhütleri daha yeni bir şeye yeniden oluşturmak isteyebilir. içine master.

Bu rebase --rebase-mergesseçeneği kullanılarak yapılabilir .


Bkz 1644c73 taahhüt küçük örneğin:

rebase-helper --make-script: birleşmeleri yeniden adlandırmak için bir bayrak tanıtmak

Sıralayıcı, şube yapısını yeniden yaratmayı amaçlayan yeni komutları öğrendi ( ruh olarak benzer --preserve-merges, ancak daha az kırık bir tasarıma sahip ).

rebase--helperYeni komutla tetiklenen bu komutları kullanarak yapılacaklar listeleri oluşturmasına izin verelim --rebase-merges.
Bunun gibi bir taahhüt topolojisi için (KAFA C'yi gösterir):

- A - B - C (HEAD)
    \   /
      D

oluşturulan yapılacaklar listesi şöyle görünecektir:

# branch D
pick 0123 A
label branch-point
pick 1234 D
label D

reset branch-point
pick 2345 B
merge -C 3456 D # C

Aradaki fark nedir --preserve-merge?
8f6aed7 numaralı taahhüt şunları açıklıyor:

Bir zamanlar, bu geliştirici şöyle düşündü: örneğin Git için Windows'un Git'in çekirdeğinin üstündeki yamalarının bir dal çalılık olarak temsil edilmesi ve çekirdek Git'in üzerine yeniden yerleştirilmesi iyi olmaz mıydı kiraz seçim 'yama serisi korumak?

Bu cevap orijinal girişimiydi: git rebase --preserve-merges.

Bununla birlikte, bu deney asla etkileşimli bir seçenek olarak tasarlanmamıştı ve sadece domuzcuk destekli git rebase --interactiveçünkü bu komutun uygulaması zaten çok, çok tanıdık görünüyordu: tasarlayan aynı kişi tarafından tasarlandı --preserve-merges: sizinki gerçekten.

Ve "gerçekten seninki" ile yazar kendisine atıfta bulunur: Johannes Schindelin ( dscho) , ( çünkü birkaç başka kahraman - Hannes, Steffen, Sebastian, ...) Git For Windows'a sahip olmamızın ( geri gün - 2009 - bu kolay değildi ). Eylül 2015'ten beri
Microsoft'ta çalışıyor . Bu eğilim 2013'te TFS ile başladı . O zamandan beri Microsoft , gezegendeki en büyük Git deposunu yönetiyor ! Ve Ekim 2018'den beri Microsoft, GitHub'ı satın aldı .

Johannes'in Nisan 2018'deki Git Merge 2018 için bu videoda konuştuğunu görebilirsiniz .

Bir süre sonra, başka bir geliştirici (sana bakıyorum, Andreas! ;-)) (uyarılarla!) Ve Git sürdürücüsüyle (iyi, geçici Git sürdürücüsü ile --preserve-mergesbirleştirilmesinin iyi bir fikir olacağına karar verdi. --interactiveJunio'nun yokluğu sırasında, kabul edilir) ve --preserve-mergestasarımın cazibesi oldukça hızlı ve anlamsız bir şekilde parçalanmaya başladı.

Jonathan Suse'dan Andreas Schwab hakkında konuşuyor .
Bazı tartışmalarını 2012'de görebilirsiniz .

Sebep? In --preserve-merges(bir veya bu konuda modunda bir birleştirme anne taahhüt herhangi taahhüt) açıkça belirtilmeyen, ancak edildi ima geçirilen işlemek adıyla pickkomutu .

Bu, örneğin, taahhütleri yeniden sıralamayı imkansız hale getirdi .
Taahhütleri şubeler arasında taşımaktan ya da tanrı yasaklamaktan, konu dallarını ikiye bölmekten bahsetmiyoruz bile.

Ne yazık ki, bu eksiklikler aynı zamanda (asıl amacı Git için Windows'un ihtiyaçlarına hizmet etmek olan, başkalarının da faydalı olabileceği ümidiyle) Windows için Git'in ihtiyaçlarına hizmet etmesini engellemiştir.

Beş yıl sonra, Git için Windows'ta zaman zaman temel Git'in etiketlerine dayanan (geliştiricinin hak edilmeyen gazabını kazanma) kısmen ilişkili olmayan, kısmen ilgisiz bir yamuk, büyük hodge-podge yama serisine sahip olmak gerçekten savunulamaz hale geldiğinde Git'in git-remote-hgWindows için rakip yaklaşımını ilk kez ortadan kaldıran kötü niyetli diziden, daha sonra bakıcı olmadan terk edilmek üzere) gerçekten savunulamazdı, " Git bahçe makası " doğdu : interaktif tabanın üstünde bir senaryo, domuz destekli, önce yeniden temellendirilecek yamaların şube topolojisini belirleyecek, daha fazla düzenleme için sahte bir yapılacaklar listesi oluşturacak, sonucu gerçek bir yapılacaklar listesine dönüştürecektir (exec eksik yapılacaklar listesi komutlarını "uygulamak" komutunu verin ve son olarak yama serisini yeni temel işlemin üstünde yeniden oluşturun.

(Git bahçe makası komut dosyasına 9055e40 numaralı taahhüdde bu düzeltme ekinde başvurulur )

Bu 2013'teydi.
Ve tasarımı bulmak ve ağaç dışı bir senaryo olarak uygulamak yaklaşık üç hafta sürdü. Söylemeye gerek yok, uygulamanın stabilize olması için birkaç yıl gerekiyordu, ancak tasarımın kendisi sağlam olduğunu kanıtladı.

Bu yama ile Git bahçe makaslarının iyiliği git rebase -ikendine gelir . Seçeneği
geçmek, --rebase-mergeskolayca anlaşılabilecek ve taahhütlerin nasıl yeniden düzenlenebileceği açık bir yapılacaklar listesi oluşturacaktır . Komutlar
ekleyerek labelve çağrılarak yeni dallar eklenebilir merge <label>.
Ve bu mod istikrarlı ve evrensel olarak kabul edildikten sonra, olan tasarım hatasını reddedebiliriz--preserve-merges .


Git 2.19 (3Ç 2018), yeni --rebase-mergesseçeneği birlikte çalıştırarak geliştirir --exec.

" --exec" Seçeneği " git rebase --rebase-merges" exec komutlarını düzeltilen yanlış yerlere yerleştirdi.

Bkz. Taahhüt 1ace63b (09 Ağu 2018) ve Johannes Schindelin ( ) tarafından f0880f7 (06 Ağu 2018) taahhüdü . (Tarafından Birleştirilmiş - Junio C Hamano - içinde 750eb11 taahhüt 2018, 20 Aug)dscho
gitster

rebase --exec: ile çalışmasını sağlayın --rebase-merges

Fikri, her birine --execbir execçağrı eklemektir pick.

fixup!/ S quash!tanıma işleminden bu yana , bu fikir "çekme, muhtemelen bir düzeltme / squash zinciri tarafından" uygulanacak şekilde genişletilmiştir, yani bir exec pick, karşılık gelen fixupveya squashsatırlarının herhangi biri arasına sokulamaz.

Mevcut uygulama Bunu başarmak için kirli bir hile kullanır: sadece / düzeltme / squash komutları orada almak varsayar ve ardından eklerexec herhangi önce satırları pickama ilk ve son tane ekler.

Tarafından oluşturulan yapılacaklar listeleri ile git rebase --rebase-merges, bu basit uygulama sorunları gösterir: varken tam olarak yanlış şey üretir label, resetve mergekomutları.

Uygulamayı tam olarak istediğimizi yapacak şekilde değiştirelim: satırları arayın pick, herhangi bir düzeltme / squash zincirini atlayın ve ardından exec satırı ekleyin . Köpürtün, durulayın, tekrarlayın.

Not: boş taahhütler yorumlanmış seçim çizgileriyle temsil edildiğinden, mümkün olduğunda yorum satırlarından önce eklemek için özen gösteririz (ve daha sonra değil, böyle bir çizgiden önce bir önceki seçim yürütme çizgisini eklemek istiyoruz ).

Bu sırada, komutlardan execsonra satırlar da ekleyin merge, çünkü bunlar ruh olarak pickkomutlara benzerler : yeni taahhütler eklerler.


Git 2.22 (2. Çeyrek 2019), bir yeniden taban ara durumlarını depolamak için refs / rewritten / hiyerarşisinin kullanımını düzeltir;

Bakınız b9317d5 , 90d31ff , 09e6564 (07 Mar 2019), Nguyễn Thái Ngọc Duy ( pclouds) .
(Göre Birleştirilmiş - Junio Cı Hamano gitster- içinde 917f2cd tamamlama 2019 09 Apr)

Refs / yeniden yazılmış / çalışma başına olduğundan emin olun

a9be29c (sıralayıcı: labelworktree-local, 2018-04-25, Git 2.19 komutu tarafından oluşturulan ref'leri çalışma ağacı refs/rewritten/başına referans alanı olarak ekler .
Ne yazık ki (benim kötü) gerçekten çalışma başına emin olmak için güncellenmesi gereken birkaç yer vardır.

- add_per_worktree_entries_to_dir()ref listesinin refs/rewritten/repo repo yerine çalışma ağacına baktığından emin olmak için güncellendi .

  • common_list[], git_path()doğru konumu döndürecek şekilde güncellenir . Buna " rev-parse --git-path" dahildir .

Bu karışıklık benim tarafımdan yaratıldı. Özel tedaviler olmadan tüm referansların çalışma başına nerede olacağı
ile bunu düzeltmeye refs/worktree,çalıştım.
Talihsiz refs / yeniden yazılan refs / worktree önce geldi, bu yüzden tüm yapabileceğimiz budur.


Git 2.24 (4. Çeyrek 2019) ile " git rebase --rebase-merges" farklı birleştirme stratejileri oluşturmayı ve stratejiye özgü seçenekleri onlara aktarmayı öğrendi.

Bakınız Elijah Newren ( ) tarafından taahhüt edilen 476998d (04 Eyl 2019 ) . Bkz e1fac53 işlemek , a63f990 işlemek , 5dcdd74 işlemek , e145d99 işlemek , 4e6023b işlemek , f67336d işlemek , a9c7107 işlemek , b8c6f24 işlemek , d51b771 işlemek , tamamlama c248d32 , 8c1e240 işlemek , tamamlama 5efed0e , 68b54f6 işlemek , 2e7bbac işlemek , 6180b20 işlemek , d5b581f tamamlama (31 Temmuz 2019) tarafındannewren
Johannes Schindelin ( dscho) .
(Göre Birleştirilmiş - Junio Cı Hamano gitster- içinde 917a319 tamamlama 2019 18 Eki)


Git 2.25 (Q1 2020) ile, koruma yerel birleştirmeyi kolaylaştırmak için yerel ve veri havuzu küresel referanslarını birbirinden ayırmak için kullanılan mantık sabittir.

Bkz. Taahhüt f45f88b , taahhüt c72fc40 , taahhüt 8a64881 , taahhüt 7cb8c92 , taahhüt e536b1f (21 Ekim 2019), SZEDER Gábor ( szeder) .
(Göre Birleştirilmiş - Junio Cı Hamano gitster- içinde db806d7 tamamlama 2019 Kasım 10)

path.c: matchdeğer girmeden işlevi çağırmatrie_find()

İmzalayan: SZEDER Gábor

'logs / refs', çalışan bir ağaca özgü yol değildir, ancak b9317d55a3 taahhüdünden beri (refs / yeniden yazılmış / çalışma başına olduğundan emin olun, 2019-03-07, v2.22.0-rc0) ' git rev-parse --git-path' sahte bir yol döndürüyor sondaki bir ' /' varsa :

$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/

trieBir yolun ortak dizine ait olup olmadığına veya ağaca özgü çalışıp çalışmadığına verimli bir şekilde karar vermek için bir veri yapısı kullanırız.

O sırada da b9317d55a3 kadar eskidir bir hata tetiklenen trieilave uygulanması kendisi 4e09cf2acf ( " path: optimize ortak dir denetim", 2015/08/31, Git v2.7.0-rc0 - birleştirme listelenen toplu 2. ).

  • Açıklamaya göre trie_find(), yalnızca "eşlemenin bir değer içerdiği anahtarın" / -veya \ 0 sonlu öneki "için verilen" fn "eşleme işlevini çağırması gerekir.
    Bu doğru değil: trie_find () işlevinin maç işlevini çağırdığı üç yer vardır, ancak bunlardan biri değerin varlığını denetlemiyor.

  • b9317d55a3 şunlara iki yeni anahtar ekledi trie:

    • ' logs/refs/rewritten' ve
    • ' logs/refs/worktree', zaten var olanın yanında ' logs/refs/bisect'.
      Bu , daha önce var olmayan ve bir değeri bağlı olmayan trie' logs/refs/' yoluna sahip bir düğümle sonuçlandı .
      ' logs/refs/' Sorgusu bu düğümü bulur ve sonra matchdeğerin varlığını denetlemeyen işlevin bir çağrı sitesine isabet eder ve böylece matchişlevi NULLdeğer olarak çağırır .
  • Zaman matchfonksiyonu check_common()bir çağrılır NULLdeğeri, sorgulanan yolu nihai olarak yukarıda gösterilen sahte yol açar değil ortak bir dizini mı ait olduğunu gösterir, 0 döndürür.

Eksik koşulu trie_find(), hiçbir zaman var olmayan bir değerle eşleştirme işlevini çağırmayacak şekilde ekleyin .

check_common() o zaman artık NULL olmayan bir değer olup olmadığını kontrol etmek zorunda kalmayacak, bu yüzden bu koşulu kaldırın.

Benzer sahte çıktıya neden olabilecek başka yolların olmadığına inanıyorum.

AFAICT, eşleşme işlevinin bir NULLdeğerle çağrılmasıyla sonuçlanan diğer anahtar ' co' (' common' ve ' config' tuşları nedeniyle ) 'dir.

Ancak, ortak dizine ait bir dizinde olmadıklarından, sonuçta çalışan ağaca özgü yol beklenir.


3
Bence bu en iyi cevap olmalı, --preserve-mergesaslında birleştirme istediğiniz gibi "korumak" değil, çok naif. Bu, birleştirme taahhütlerini ve ana taahhüt ilişkilerini korumanıza izin verirken, size etkileşimli bir rebase esnekliği sağlar. Bu yeni özellik harika & bu iyi yazılmış SO cevap olmasaydı, ben bilemezdim!
egucciar


1
Bu Q / A'da olduğu gibi
taahhütlerin yığınlarını

1
Oh, gerçekten bir süredir aradığım şey bu! Ben manuel geçici çözümü hangi bir hayali bir bütün birleştirmeleri katılmadan kesinleştirme oluşturması gerektiğini gibi durumlar için.
carnicer

Tipik Git. Basit bir soru sormaya cesaret edersiniz ve büyük olasılıkla Git'in geçmişini, iç algoritmaları, tüm dağınık uygulama ayrıntılarını öğrenmek zorundasınız ve ayrıca neler olduğunu anlamak için grafik teorisinde büyük bir şeye ihtiyacınız var.
Dimitris
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.