Git birleştirme yerine Git rebase'i ne zaman kullanırsınız?


1548

Git rebase vs. Git merge kullanılması ne zaman önerilir?

Başarılı bir tekrardan sonra hala birleştirmem gerekiyor mu?




6
Rebase kullanmak isteyen insanlarla ilgili bir sorun, kodlarını düzenli olarak itmelerini engellemesidir. Yani temiz tarih istemek onların kodlarını paylaşmasını engeller, ki bu daha önemli
static_rtti

9
@static_rtti: Bu doğru değil. Değişikliklerinizi düzenli olarak yapmanıza engel oluyorsa rebase tabanlı bir akış yanlış kullanıyorsunuz.
juzzlin

5
Andrew Arnott'in cevabının ve Pace'ın cevabının daha önce yayınlanmadığı gerçek bir utanç , çünkü bu soruyu zaten birçok oy toplayan önceki cevaplardan daha kapsamlı olarak cevaplıyorlar.
Mark Booth

Yanıtlar:


1136

Kısa versiyon

  • Birleştirme bir daldaki tüm değişiklikleri alır ve bunları tek bir taahhütte başka bir dalda birleştirir.
  • Rebase, dalladığım noktanın yeni bir başlangıç ​​noktasına taşınmasını istediğimi söylüyor

Peki ne zaman birini kullanıyorsun?

Birleştirmek

  • Tek bir özellik geliştirmek amacıyla bir şube oluşturduğunuzu varsayalım. Bu değişiklikleri ustaya geri getirmek istediğinizde, muhtemelen birleştirme istersiniz (tüm geçici taahhütleri korumakla ilgilenmezsiniz).

rebase

  • İkinci bir senaryo, bazı geliştirmeler yapmaya başladığınız ve daha sonra başka bir geliştirici ilgisiz bir değişiklik yaptıysanız olacaktır. Muhtemelen çekimlerinizi geçerli sürümden depoya dayandırmak için çekin ve yeniden adlandırmak istersiniz .

105
@Rob, birleştirme sırasında geçici taahhütlerin sürdürülmesinden bahsetti. Varsayılan olarak B dalını (üzerinde çalıştığınız bir özellik dalını) M dalına (ana dal) birleştirerek, iki ayrılandan bu yana B'de yapılan her bir taahhüt için M'de bir taahhüt oluşturacağına inanıyorum. Ancak --squash seçeneğini kullanarak birleştirirseniz, B dalında yapılan tüm taahhütler "bir araya getirilir" ve M dalında tek bir işlem olarak birleştirilir ve ana dalınızdaki günlüğü güzel ve temiz tutar. Bağımsız olarak çalışan ve ustaya geri dönen çok sayıda geliştiriciniz varsa ezmek muhtemelen istediğiniz şeydir.
spaaarky21

19
@ Spaaarky21'in birleştirme hakkındaki varsayımının doğru olmadığına inanıyorum. B dalını ana M ile birleştirirseniz, düz veya - kare birleştirme kullansanız da, M'de tek bir taahhüt (B'nin birden fazla taahhütü olsa bile) olacaktır. --Squash'in yapacağı şey, ebeveyn olarak B'ye olan referansı ortadan kaldırmaktır. İyi bir görselleştirme burada: syntevo.com/smartgithg/howtos.html?page=workflows.merge
jpeskin

14
@jpeskin Gördüğüm bu değil. Doğrulamak için hızlı bir test yaptım. Metin dosyası, inityeni bir repo, adddosya ve ile bir dizin oluşturun commit. Yeni bir özellik dalını ( checkout -b feature.) Teslim alma Metin dosyasını değiştirin, özellik dalında iki yeni işlem olacak şekilde işlem yapın ve tekrarlayın. Sonra checkout masterve merge feature. İçinde log, ustalık üzerine ilk taahhüdümü, ardından özellikten birleştirilen ikisini görüyorum. Siz merge --squash feature, özellik master ile birleştirilir, ancak taahhüt edilmezse , bu yüzden master üzerinde sadece yeni taahhüt sizin yaptığınız olacaktır.
spaaarky21

21
@ spaaarky21 Görünüşe göre ikimiz de yarı haklıyız. Bir hızlı ileri birleştirme mümkün olduğunda (örneğinizde olduğu gibi) git, özellik dalındaki B tüm taahhütleri dahil etmeyi varsayılan olarak kullanır (veya önerdiğiniz gibi, --squash'i tek bir taahhütte birleştirmek için kullanabilirsiniz). Ancak, birleştirdiğiniz iki ıraksak dal M ve B olduğu durumda, git, M ile birleştirildiyse (--squash kullansanız da kullanmasanız da) B dalından alınan tüm taahhütleri içermez.
jpeskin

6
Neden bu cevapta "(tüm geçici taahhütleri korumakla ilgilenmiyorsun)"? '09'da bir anlam ifade etmedi ve şimdi bir anlam ifade etmiyor. Ayrıca, yalnızca başka bir geliştirici ihtiyaç duyduğunuz ilgili değişiklikleri yaptıysa yeniden temsili yapmak istersiniz - ilgisiz değişiklikler yapmışlarsa, özellik dalınız yine de çatışma olmadan kolayca birleşmeli ve geçmişiniz korunacaktır.
Mark Booth

372

Basit. Rebase ile işiniz için yeni bir üs olarak başka bir şube kullanmayı söylüyorsunuz .

Örneğin bir şubeniz varsa master, yeni bir özellik uygulamak için bir şube oluşturursunuz ve bunu adlandırdığınızı söylüyorsunuz cool-feature, elbette ana şube yeni özelliğinizin temelidir.

Şimdi belirli bir noktada masterşubeye uyguladığınız yeni özelliği eklemek istiyorsunuz . Sadece şubeye geçebilir masterve cool-featureşubeyi birleştirebilirsiniz :

$ git checkout master
$ git merge cool-feature

Ancak bu şekilde yeni bir kukla taahhüt eklendi. Spagetti geçmişinden kaçınmak istiyorsanız, yeniden pazarlayabilirsiniz :

$ git checkout cool-feature
$ git rebase master

Ve sonra birleştirin master:

$ git checkout master
$ git merge cool-feature

Bu kez, konu dalı aynı ana öğeye ve yeni özellikle ilgili taahhütlere sahip olduğundan, birleştirme yalnızca hızlı bir şekilde ilerleyecektir.


31
but this way a new dummy commit is added, if you want to avoid spaghetti-history- nasıl kötü?
ス レ ッ ク ス

6
Ayrıca, --no-ff birleştirme bayrağı çok yararlıdır.
Aldo 'xoen' Giambelluca

3
@ ア レ ッ ク ス kullanıcı Sean Schofieldbir yorumda koyar gibi: "Rebase de güzel çünkü u zaman sonunda ur şeyler geri master (daha önce açıklandığı gibi önemsiz) içine birleştirmek bir ur taahhüt tarihinin" üst "oturan var. Özelliklerin yazılabildiği ancak birkaç hafta sonra birleştirilebildiği projeler, bunları sadece ana ile birleştirmek istemezsiniz, çünkü bunlar tarihte ana yolun içine "doldurulur". Bu son özellik "üstte" dir. Teslim tarihlerinin korunduğunu unutmayın - rebase bu bilgileri değiştirmez. "
Adrien Be

4
Tüm bu terimler (unutmayın - Muhakkak burada tekrar ayılar düşünüyorum merge, rebase, fast-forwardvs.) yönlendirilmiş Mercury grafik belirli manipülasyonlara kastediyoruz. Akıldaki bu zihinsel model ile akıl yürütmeleri daha kolay hale gelir.
Roy Tinker

10
@Aldo Yeniden temel alan bir tarih hakkında "temiz" veya "düzenli" bir şey yok. Genellikle pis ve IMHO korkunç çünkü gerçekten ne olduğu hakkında hiçbir fikriniz yok. "En temiz" Git geçmişi, gerçekte meydana gelen tarihtir. :)
Marnen Laibow-Koser

269

TSamper tarafından belirtilen kendi cevabımı tamamlamak için ,

  • bir yeniden birleştirme genellikle bir birleştirme işleminden önce yapmak için iyi bir fikirdir, çünkü fikir, Yşubenize Bbirleştireceğiniz dalın çalışmasını bütünleştirmenizdir .
    Ama yine, birleştirme önce, içeri herhangi bir çatışmayı çözmek için (: "içinde şubesinden son noktadan başlayarak benim dalında işimi tekrar olarak, "Rebase" yani dalı B).
    İçin daldan doğru müteakip birleştirme yapılırsa şube Bhızlı ileri olabilir.

  • bir birleştirme hedef dalını doğrudan etkiler B, yani birleşmelerin önemsiz olması daha iyi olur, aksi takdirde dalın Bkararlı bir duruma geri dönmesi uzun sürebilir (tüm çatışmaları çözme zamanı)


Rebase'den sonra birleşmenin anlamı nedir?

Anlattığım durumda, şubemi tekrar gözden geçiriyorum B, sadece işimi daha yakın bir noktadan tekrar oynatma fırsatına sahip olmak için B, ancak şubemde kalırken.
Bu durumda, "yeniden oynatılan" çalışmamı getirmek için hala birleştirme gerekir B.

Diğer senaryo ( örneğin Git Ready'de açıklanmıştır ), çalışmanızı doğrudan Bbir rebase aracılığıyla getirmektir (tüm taahhütlerinizi koruyan veya hatta bunları interaktif bir rebase üzerinden yeniden sipariş etme fırsatı veren).
Bu durumda (B dalındayken yeniden pazarladığınız yerde) haklısınız: daha fazla birleştirmeye gerek yok:

Birleştirilmediğimizde veya yeniden baslamadığımızda varsayılan olarak bir Git ağacı

rebase1

biz rebasing olsun:

rebase3

Bu ikinci senaryo tamamen ilgili: yeni özelliği nasıl tekrar master haline getirebilirim?

Demek istediğim, ilk rebase senaryosunu tanımlayarak herkese, bir rebase'in de bunun için bir ön adım olarak kullanılabileceğini hatırlatmak ("yeni özelliği tekrar ustaya dönüştürmek").
Rebase'i ilk önce yeni özellik dalında "" içine master getirmek için kullanabilirsiniz: Rebase yeni özellik taahhütlerini tekrardan HEAD master, ancak yeni özellik dalında tekrar oynatarak şube başlangıç ​​noktanızı eski bir ana taahhütten etkili bir şekilde taşıyacaktır HEAD-master.
Yani herhangi çatışmaları çözmek için izin verir senin (izin usta senin çakışma çözümleme aşaması çok uzun sürerse paralel olarak gelişmeye devam etmek iken, izolasyon anlamına) şube.
Sonra ana ve birleştirme geçebilirsiniz new-feature(veya rebase new-featureüzerine mastersize yapılan hareketin kaydedilmesini korumak istiyorsanız sizinnew-feature dalı).

Yani:

  • "Rebase vs. merge", bir çalışmayı içe aktarmanın iki yolu olarak görülebilir master.
  • Ancak "rebase then merge" ilk önce çatışmayı tek başına çözmek, sonra çalışmanızı geri getirmek için geçerli bir iş akışı olabilir.

17
Rebase'den sonra birleşme, çatışmaları çözmek zorunda kalmadan önemsiz bir hızlı ilerlemedir.
obecalp

4
@obelcap: Eğer tüm problem çatışma atın: Gerçekten de, bu tür fikir olduğunu sizin , çevre (Rebase yeni-özellik şube içinde usta) ve ardından eş usta yeni özellik birleştirme: 1 piko-saniye (hızlı ileri) eğer efendinin evrimi yoktu
VonC

27
Rebase de güzel çünkü sonunda bir kez (bir kez daha önce açıklandığı gibi önemsiz) eşyalarınızı master birleştirmek taahhüt işinin "üst" oturmuş var. Özelliklerin yazılabildiği ancak birkaç hafta sonra birleştirilebileceği daha büyük projelerde, bunları sadece master ile birleştirmek istemezsiniz, çünkü bunlar tarihte ana yolun içine "doldurulur". Şahsen git log yapmayı ve o son özelliği "üstte" görmeyi seviyorum. İşleme tarihlerinin korunduğunu unutmayın - rebase bu bilgileri değiştirmez.
Sean Schofield

3
@Joe: zihinsel olarak, "değişikliklerden herhangi birini (özel şubemde ayrı ayrı yapılır) diğer dalın üzerine tekrar oynat, ancak yeniden yapılanma bittikten sonra beni özel şubemde bırak" diyorsun. Bu, yerel denetim tarihini temizlemek için iyi bir fırsattır. Bkz. "Git iş akışı": sandofsky.com/blog/git-workflow.html
VonC

4
@scoarescoare, yerel değişikliklerinizin en son yukarı akış şubesinin üstünde nasıl uyumlu olduğunu görmektir . Taahhütlerinizden biri bir çatışma çıkarsa, bunu hemen göreceksiniz. Birleştirme, kendi yerel taahhütleriniz arasında hangisinin söz konusu çatışmayı eklediğini görmenin kolay bir yolu olmadan birçok çatışmayı tetikleyebilecek yalnızca bir (birleştirilmiş) taahhüt sunar. Böylece, daha temiz bir geçmişe ek olarak , yukarı akış dalının getirdiği tüm değişikliklerin (tek bir birleştirmeye dökülen ) aksine, taahhüt ettiğiniz değişiklikleri taahhüt ederek (yeniden taban tarafından yeniden yürütülür) daha kesin bir şekilde görebilirsiniz .
VonC

229

TL; DR

Herhangi bir şüpheniz varsa, birleştirme kullanın.

Kısa cevap

Rebase ve birleştirme arasındaki tek farklar:

  • Tarihin ortaya çıkan ağaç yapısı (genellikle sadece bir taahhüt grafiğine bakıldığında fark edilir) farklıdır (biri dallara sahip olacak, diğeri olmayacaktır).
  • Birleştirme genellikle fazladan bir taahhüt oluşturur (örn. Ağaçtaki düğüm).
  • Birleştirme ve yeniden oluşturma çatışmaları farklı şekilde ele alır. Rebase, çatışmanın her seferinde bir taahhütte bulunacak ve birleştirmenin hepsini bir kerede sunacağı.

Bu nedenle kısa cevap, geçmişinizin nasıl görünmesini istediğinize göre yeniden taban oluşturmak veya birleştirmek .

Uzun cevap

Hangi işlemi kullanacağınızı seçerken dikkate almanız gereken birkaç faktör vardır.

Değişiklik aldığınız şube, ekibiniz dışındaki diğer geliştiricilerle paylaşılıyor mu (ör. Açık kaynak, herkese açık)?

Eğer öyleyse, yeniden pazarlamayın. Rebase şubeyi yok eder ve bu geliştiriciler kullanılmadıkça bozulan / tutarsız depolara sahip olacaktır git pull --rebase. Bu, diğer geliştiricileri hızlı bir şekilde üzmek için iyi bir yoldur.

Geliştirme ekibiniz ne kadar yetenekli?

Rebase yıkıcı bir işlemdir. Bu, doğru bir şekilde uygulamazsanız, kararlı çalışmayı kaybedebilir ve / veya diğer geliştiricinin depolarının tutarlılığını bozabilirsiniz.

Geliştiricilerin hepsinin, şirketlerin dallanma ve birleşme ile ilgilenmek için özel personel alabilecekleri bir zamandan geldiği ekiplerde çalıştım. Bu geliştiriciler Git hakkında çok şey bilmiyorlar ve çok fazla şey bilmek istemiyorlar. Bu ekiplerde herhangi bir sebepten ötürü yeniden temellendirme önerme riskiyle karşılaşmam.

Şubenin kendisi faydalı bilgileri temsil ediyor mu?

Bazı ekipler, her dalın bir özelliği (veya hata düzeltme veya alt özellik vb.) Temsil ettiği özellik başına dal modelini kullanır. Bu modelde dal, ilgili taahhüt kümelerinin belirlenmesine yardımcı olur. Örneğin, bir dalın birleştirmesini geri alarak bir özelliği hızlı bir şekilde geri alabilir (adil olmak gerekirse, bu nadir bir işlemdir). Veya iki özelliği karşılaştırarak bir özelliği farklılaştırın (daha yaygın). Rebase şubeyi yok edecekti ve bu kolay olmayacaktı.

Ayrıca, geliştirici başına şube modelini kullanan ekipler üzerinde de çalıştım (hepimiz oradaydık). Bu durumda, şubenin kendisi herhangi bir ek bilgi iletmez (taahhüt zaten yazara sahiptir). Yeniden temellendirmede herhangi bir zarar olmaz.

Herhangi bir nedenle birleştirmeyi geri döndürmek ister misiniz?

Bir rebase'i geri almak (geri almada olduğu gibi), bir birleştirmeyi geri almakla karşılaştırıldığında (rebase'in çatışmaları varsa) oldukça zor ve / veya imkansızdır. Geri dönmek isteyeceğiniz bir şans olduğunu düşünüyorsanız, birleştirme kullanın.

Bir ekip üzerinde mi çalışıyorsunuz? Eğer öyleyse, bu dalda ya hep ya hiç yaklaşmaya istekli misiniz?

Rebase işlemlerinin uygun bir şekilde çekilmesi gerekir git pull --rebase. Kendiniz çalışıyorsanız, uygun zamanda hangisini kullanmanız gerektiğini hatırlayabilirsiniz. Eğer bir ekip üzerinde çalışıyorsanız, bu koordine etmek çok zor olacaktır. Bu yüzden çoğu rebase iş akışı tüm birleşmelerde (ve git pull --rebasetüm çekimlerde) rebase kullanılmasını önerir .

Ortak mitler

Birleştirme tarihi yok eder (squashes taahhüt eder)

Aşağıdaki birleştirmeye sahip olduğunuzu varsayarsak:

    B -- C
   /      \
  A--------D

Bazı insanlar, birleştirme işleminin işlem geçmişini "yok ettiğini" söyleyecektir, çünkü yalnızca ana dalın (A - D) günlüğüne bakarsanız, B ve C'de yer alan önemli işlem mesajlarını kaçırırsınız.

Eğer bu doğru olsaydı, böyle sorularımız olmazdı . Temel olarak, açıkça görmemenizi istemediğiniz sürece (--first-parent kullanarak) B ve C'yi göreceksiniz. Bunu kendiniz denemek çok kolay.

Rebase, daha güvenli / daha basit birleştirmelere olanak tanır

İki yaklaşım farklı bir şekilde birleşir, ancak birinin her zaman diğerinden daha iyi olduğu ve geliştiricinin iş akışına bağlı olabileceği açık değildir. Örneğin, bir geliştirici düzenli olarak taahhütte bulunursa (örneğin, işten eve geçişte günde iki kez taahhüt eder), o zaman belirli bir dal için çok fazla taahhüt olabilir. Bu taahhütlerin çoğu nihai ürün gibi görünmeyebilir (her özellik için bir veya iki kez yaklaşımımı yeniden düzenleme eğilimindeyim). Başka biri ilgili bir kod alanı üzerinde çalışıyorsa ve değişikliklerimi yeniden oluşturmaya çalıştıysa, bu oldukça sıkıcı bir işlem olabilir.

Rebase daha havalı / daha seksi / daha profesyonel

Eğer takma nasıl rmüzere rm -rf"Zaman tasarrufu" o zaman belki Rebase size göre.

Benim görüşüm

Her zaman bir gün Git rebase'in problemi çözen harika bir araç olduğu bir senaryoyla karşılaşacağımı düşünüyorum. Sanırım Git reflog sorunumu çözen harika bir araç. Git ile beş yıldır çalışıyorum. Olmadı.

Dağınık tarihler benim için hiçbir zaman gerçekten bir sorun olmadı. Taahhüt tarihimi hiç heyecan verici bir roman gibi okumadım. Geçmişe ihtiyaç duyduğum çoğu zaman Git suçunu veya Git bisect'i kullanacağım zaten. Bu durumda, birleştirme taahhüdüne sahip olmak benim için gerçekten yararlıdır, çünkü birleştirme sorunu ortaya koyarsa, bu benim için anlamlı bir bilgidir.

Güncelleme (4/2017)

Genel tavsiyem hala geçerli olmasına rağmen, rebase kullanımında kişisel olarak yumuşadığımı belirtmek zorundayım. Son zamanlarda Angular 2 Material projesiyle çok etkileşime giriyorum . Çok temiz bir taahhüt geçmişi tutmak için rebase kullandılar. Bu, hangi kusurun belirli bir hatayı düzelttiğini ve bu taahhüdün bir sürüme dahil edilip edilmediğini çok kolay bir şekilde görmemi sağladı. Rebase'i doğru kullanmanın harika bir örneği.


5
Doğrulanmış cevap olmalı.
Mik378

Bu kesinlikle en iyi cevap. Özellikle en son güncellemedeki net açıklama ile. Git geçmişini temiz ve net tutmaya yardımcı olur, ancak güvenle kullanın.
zquintana

5
Bu cevabı çoğunlukla seviyorum. Ancak: Rebase "temiz" bir tarih oluşturmaz. Daha doğrusal bir tarih yapar, ancak bu aynı şey değildir, çünkü şimdi her bir taahhüdün saklandığı çok fazla "kir" kim bilir? En temiz, en net Git geçmişi, dalı tutan ve bütünlüğü koruyan geçmişidir.
Marnen Laibow-Koser

3
"Ortak efsane, B ve C taahhütlerini görürsünüz": Mutlaka değil !! Aslında B ve C'yi yalnızca birleştirme hızlı ileri bir birleştirme ise görürsünüz ve bu ancak hiçbir çatışma yoksa mümkündür. Çatışmalar varsa, tek bir taahhüt alırsınız! Bununla birlikte, önce master'ı özelliğe birleştirebilir ve orada çakışmaları çözebilir ve daha sonra özelliği master ile birleştirirseniz, B ve C taahhütlerini alırsınız ve (ilk) master'dan geçmişinizdeki birleştirme işleminden tek bir X komutu alırsınız.
Jeremy Benks

çok iyi bir açıklama! Daha fazla iptal edilmelidir!
Ocak'ta

185

Burada birçok cevap, birleştirmenin tüm taahhütlerinizi bire dönüştürdüğünü ve bu nedenle taahhütlerinizi korumak için rebase kullanmanızı önerir. Bu yanlış. Taahhütlerinizi zaten ittiyseniz kötü bir fikir .

Birleştirme yok değil senin kaydedilmesini yoketmek. Birleştirme tarihi korur! (sadece gitk'e bakın) Rebase, tarihi ittikten sonra kötü bir şey olan yeniden yazar .

Birleştirme kullanın - daha önce ittiğinizde yeniden pazarlamayın.

İşte Linus'un (Git'in yazarı) üstlenmesi (şimdi Wayback Machine tarafından kurtarıldığı gibi kendi blogumda barındırılıyor ). Gerçekten iyi bir okuma.

Veya aşağıda aynı fikrin kendi versiyonumu okuyabilirsiniz.

Bir ana dalda yeniden adlandırma:

  • taahhütlerin nasıl yaratıldığı hakkında yanlış bir fikir verir
  • iyi test edilmemiş bir grup ara taahhütle ustayı kirletir
  • orijinal konu dalının oluşturulduğu zaman ile yeniden baslanacağı zaman arasında ustalaşmak için yapılan değişiklikler nedeniyle bu ara işlemlere derleme sonları ekleyebilir.
  • master için iyi yerler bulmayı zorlaştırır.
  • Taahhütlerdeki zaman damgalarının ağaçtaki kronolojik sıralarıyla hizalanmamasına neden olur. Böylece A komutunun B komutunun ustasından önce geldiğini görürsünüz, ancak B komutu önce yazılmıştır. (Ne?!)
  • Konu dalındaki bireysel taahhütlerin her biri, bireysel olarak çözülmesi gereken birleştirme çatışmalarını içerebilir (her bir taahhütte neler olduğu hakkında tarihte daha fazla yalan söyleme).
  • tarihin yeniden yazılmasıdır. Yeniden baslanan şube herhangi bir yere itildiyse (kendinizden başka biriyle paylaşılırsa), geçmişi yeniden yazdığınızdan bu şubeye sahip olan herkesi mahvettiniz.

Buna karşılık, bir konu dalını ana birime birleştirmek:

  • ana daldan konu dalına güncelleştirme işlemine yardımcı olacak birleştirme de dahil olmak üzere, konu dallarının oluşturulduğu geçmişin tarihçesini korur. Geliştiricinin, oluştururken hangi kodla çalıştığı konusunda gerçekten doğru bir fikir edinebilirsiniz.
  • master çoğunlukla birleşmelerden oluşan bir daldır ve bu birleştirme taahhütlerinin her biri, tarihte genellikle kontrol edilmesi güvenli olan “iyi noktalar” dır, çünkü konu dalı entegre olmaya hazırdır.
  • bir konu dalında olmaları da dahil olmak üzere, konu dalının tüm bireysel taahhütleri korunur, bu nedenle bu değişiklikleri izole etmek doğaldır ve gerektiğinde ayrıntılı inceleme yapabilirsiniz.
  • birleştirme çakışmalarının yalnızca bir kez (birleştirme noktasında) çözülmesi gerekir; bu nedenle, konu dalında yapılan ara taahhüt değişikliklerinin bağımsız olarak çözülmesi gerekmez.
  • birden çok kez sorunsuz yapılabilir. Konu dalınızı periyodik olarak master'a entegre ederseniz, insanlar konu dalını oluşturmaya devam edebilir ve bağımsız olarak birleştirilmeye devam edebilir.

3
Ayrıca git merge, "--no-ff" (hızlı ileri) seçeneği ile belirli bir birleştirme tarafından getirilen tüm değişiklikleri kolayca geri almanıza olanak tanır.
Tiago

3
Sadece daha açık bir şekilde ifade edin: 'Daha önce ittiğiniz zaman' durumuna atıfta bulunuyorsunuz - bu cesur olmalıdır. Linus'a bağlantı gönderisi harika, btw.
honzajde

2
ancak, konu dalını PR aracılığıyla master'a birleştirmeden önce (master değil, şubenizdeki çatışmaları çözmek için) master'dan konu dalınıza "güncelleme" yapmak en iyi yöntem değil mi? Bunu, çoğu konu dalının son taahhüt olarak "şube masterını konu -..." ile birleştirmesi gibi yapıyoruz, ancak burada yeniden basmanın bir "özelliği" olarak listeleniyor ve kimse birleştirme için bahsetmiyor ...?
ProblemsOfSumit

2
@AndrewArnott "Çoğu konu dalı, hedef dallarına çakışmadan birleşebilmelidir" 30 dalda 20 geliştirici çalışırken bu nasıl mümkün olmalıdır? Sizinkiler üzerinde çalışırken birleştirme olacak - bu yüzden bir PR oluşturmadan önce konu dalını hedeften güncellemelisiniz ... hayır?
ProblemsOfSumit

3
Genellikle değil, @Sumit. Git, her iki dalda veya her iki dalda değişiklik yapılsa bile, her iki yönde de birleştirilebilir. Yalnızca aynı kod satırları (veya çok yakın) iki dalda değiştirildiğinde çakışmalar oluşur. Bu, herhangi bir takımda sık sık olursa, çatışmaları çözmek bir vergi olduğundan ve onları yavaşlattığından ekip işi nasıl dağıttıklarını yeniden düşünmelidir.
Andrew Arnott

76

TLDR: En önemli olana bağlıdır - düzenli bir geçmiş veya kalkınma dizisinin gerçek bir temsili

Düzenli bir geçmiş en önemlisiyse, önce yeniden temel oluşturur ve ardından değişikliklerinizi birleştirirsiniz, bu nedenle yeni kodun tam olarak ne olduğu açıktır. Şubenizi zaten ittiyseniz, sonuçlarla başa çıkmadığınız sürece yeniden pazarlamayın.

Dizinin gerçek temsili en önemliyse, yeniden temellendirmeden birleşirsiniz.

Birleştirme şu anlama gelir: Değişikliklerimi hedefe birleştiren yeni bir taahhüt oluşturun. Not: Bu yeni taahhüdün iki ebeveyni olacaktır - taahhüt dizinizden en son taahhüt ve birleştirdiğiniz diğer şubenin son taahhüdü.

Rebase anlamı: Mevcut taahhütler setimi ipuçları olarak kullanarak tamamen yeni bir taahhüt serisi oluştur. Başka bir deyişle, bunları yeniden bastığım noktadan yapmaya başlasaydım değişikliklerinizin nasıl görüneceğini hesaplayın. Bu nedenle, yeniden paylaşımdan sonra değişikliklerinizi yeniden test etmeniz gerekebilir ve yeniden yapılandırma sırasında birkaç ihtilafınız olabilir.

Bu göz önüne alındığında, neden geri dönesin? Sadece gelişim tarihini açık tutmak için. Diyelim ki X özelliği üzerinde çalışıyorsunuz ve işiniz bittiğinde değişikliklerinizi birleştiriyorsunuz. Hedef artık "X özelliği eklendi" satırlarında bir şey söyleyecek tek bir işleme sahip olacak. Şimdi, birleştirmek yerine, yeniden baslayıp sonra birleştirdiyseniz, hedef geliştirme geçmişi tüm bireysel taahhütleri tek bir mantıksal ilerleme içinde içerecektir. Bu, daha sonra değişikliklerin gözden geçirilmesini çok daha kolay hale getirir. 50 geliştirici her zaman çeşitli özellikleri birleştiriyorsa, geliştirme geçmişini incelemenin ne kadar zor olduğunu düşünün.

Bununla birlikte, üzerinde çalıştığınız dalı zaten yukarı doğru ittiyseniz, yeniden pazarlamamalısınız, bunun yerine birleştirmelisiniz. Yukarı doğru itilmemiş dallar için, yeniden taban oluşturma, test etme ve birleştirme.

Yeniden pazarlamak isteyebileceğiniz başka bir zaman, yukarı doğru itmeden önce şubenizdeki taahhütlerden kurtulmak istediğiniz zamandır. Örneğin: Bazı hata ayıklama kodlarını erkenden tanıtan ve diğer kodlar bu kodu temizleyen daha fazla taahhütte bulunur. Bunu yapmanın tek yolu etkileşimli bir rebase gerçekleştirmektir:git rebase -i <branch/commit/tag>

GÜNCELLEME: Git'i doğrusal olmayan geçmişi desteklemeyen bir sürüm kontrol sistemine arabirim oluşturmak için kullanırken de rebase'i kullanmak istersiniz ( örneğin Subversion ). Git-svn köprüsünü kullanırken, Subversion'a birleştirdiğiniz değişikliklerin, bagajdaki en son değişikliklerin üstünde sıralı bir değişiklik listesi olması çok önemlidir. Bunu yapmanın yalnızca iki yolu vardır: (1) Değişiklikleri manuel olarak yeniden oluşturun ve (2) Çok daha hızlı olan rebase komutunu kullanarak.

GÜNCELLEME 2: Bir yeniden tabanı düşünmenin bir başka yolu, geliştirme stilinizden taahhütte bulunduğunuz depoda kabul edilen stile bir tür eşleme sağlamasıdır. Diyelim ki küçük, küçük parçalar halinde iş yapmak istiyorsunuz. Bir yazım hatasını düzeltmek için bir taahhüdünüz, kullanılmayan kodlardan kurtulmak için bir taahhüdünüz var. Yapmanız gerekeni bitirdiğinizde, uzun bir işiniz olur. Şimdi, büyük taahhütleri teşvik etmek için taahhüt ettiğiniz deponun diyelim ki yaptığınız iş için biri bir veya belki iki taahhüt bekleyebilir. Taahhüt dizenizi nasıl alıyorsunuz ve bunları beklenen şeylere nasıl sıkıştırıyorsunuz? İnteraktif bir rebase kullanırsınız ve minik taahhütlerinizi daha az büyük parçalara ayırırsınız. Tersi gerekliyse aynı şey geçerlidir - tarzınız birkaç büyük taahhütse, ancak depo uzun taahhütler dizisi talep etti. Bunu yapmak için de bir rebase kullanırsınız. Bunun yerine birleştirilmiş olsaydınız, artık taahhüt stilinizi ana depoya aşıladınız. Çok sayıda geliştirici varsa, bir süre sonra birkaç farklı taahhüt stiline sahip bir geçmişi takip etmenin ne kadar zor olacağını hayal edebilirsiniz.

GÜNCELLEME 3: Does one still need to merge after a successful rebase?Evet, biliyorsun. Bunun nedeni, bir tabanın esasen taahhütlerin "değiştirilmesini" içermesidir. Yukarıda söylediğim gibi, bu taahhütler hesaplanır, ancak dallanma noktasından 14 taahhütünüz varsa, o zaman rebase'inizde hiçbir şeyin yanlış olmadığını varsayarsak, (taahhüt ettiğiniz noktanın) ardından 14 taahhüt önde olacaksınız. Rebase yapılır. Rebase'den önce bir şubeniz vardı. Sonra aynı uzunlukta bir dalınız olacak. Değişikliklerinizi yayınlamadan önce yine de birleştirmeniz gerekir. Başka bir deyişle, istediğiniz kadar yeniden tabandan ayırın (yine, yalnızca değişikliklerinizi akış yukarı itmediyseniz). Yalnızca yeniden pazarladıktan sonra birleştirin.


1
Master ile birleşmek hızlı bir ileriye yol açabilir. Bir özellik dalında, küçük hatalara sahip olan veya derlemeyen bazı taahhütler olabilir. Bir özellik dalında yalnızca birim sınama yaparsanız, entegrasyonumda bazı hatalar geçiyor. Master ile birleştirmeden önce entegrasyon testleri gereklidir ve bazı hatalar gösterebilir. Bunlar düzeltildiyse, özellik entegre edilebilir. Buggy kodunu ustalaştırmak istemediğiniz için, tüm taahhütlerin hızlı bir şekilde ilerlemesini önlemek için bir rebase gerekli görünüyor.
mbx

1
@ mbx git merge, --no-ffbirleştirme işlemi yapmaya zorlayan seçeneği destekler .
Gavin S. Yancey

63

Birleştirme kesinlikle değişiklikleri entegre etmenin en kolay ve en yaygın yolu olsa da, tek değil: Rebase alternatif bir entegrasyon aracıdır.

Birleştirmeyi Biraz Daha İyi Anlamak

Git birleştirme gerçekleştirdiğinde üç işlem gerçekleştirir:

  • (1) Ortak ata taahhüdü. Bir projedeki iki dalın tarihini takip ederseniz, her zaman en az bir ortak taahhütleri vardır: bu noktada, her iki dal da aynı içeriğe sahipti ve daha sonra farklı şekilde gelişti.
  • (2) + (3) Her dalın uç noktaları. Bir entegrasyonun amacı, iki şubenin mevcut durumlarını birleştirmektir. Bu nedenle, ilgili son revizyonları özel ilgi çekmektedir. Bu üç taahhüdü birleştirmek hedeflediğimiz entegrasyon ile sonuçlanacaktır.

Hızlı İleri Alma veya Birleştirme İşlemi

Çok basit durumlarda, iki daldan birinin dallanma gerçekleştiğinden beri yeni taahhütleri yoktur - en son taahhüdü hala ortak atadır.

Resim açıklamasını buraya girin

Bu durumda, entegrasyonun gerçekleştirilmesi son derece basittir: Git diğer dalın tüm taahhütlerini ortak ata taahhüdünün üzerine ekleyebilir. Git'te bu en basit entegrasyon şekline "hızlı ileri" birleştirme denir. Her iki dal da aynı tarihi paylaşır.

Resim açıklamasını buraya girin

Bununla birlikte, birçok durumda, her iki dal ayrı ayrı ilerledi.

Resim açıklamasını buraya girin

Bir entegrasyon yapmak için Git, aralarındaki farkları içeren yeni bir taahhüt oluşturmak zorunda kalacak - birleştirme taahhüdü.

Resim açıklamasını buraya girin

İnsan Taahhütleri ve Birleştirme Taahhütleri

Normalde, bir taahhüt insan tarafından dikkatle yaratılır. Sadece ilgili değişiklikleri saran ve bir yorumla açıklama ekleyen anlamlı bir birimdir.

Birleştirme taahhüdü biraz farklıdır: bir geliştirici tarafından oluşturulmak yerine Git tarafından otomatik olarak oluşturulur. Ve bir dizi ilgili değişikliği sarmak yerine, amacı bir düğüm gibi iki dalı birbirine bağlamaktır. Daha sonra bir birleştirme işlemini anlamak istiyorsanız, her iki dalın geçmişine ve ilgili taahhüt grafiğine bakmanız gerekir.

Rebase ile entegrasyon

Bazı insanlar böyle otomatik birleştirme taahhütleri olmadan gitmeyi tercih eder. Bunun yerine, projenin tarihinin sanki tek bir düz çizgide evrilmiş gibi görünmesini istiyorlar. Bir noktada birden fazla şubeye ayrıldığına dair hiçbir belirti kalmadı.

Resim açıklamasını buraya girin

Adım adım bir rebase operasyonuna geçelim. Senaryo önceki örneklerle aynıdır: şube-B'den şube-A'ya değişiklikleri entegre etmek istiyoruz, ama şimdi rebase'i kullanarak.

Resim açıklamasını buraya girin

Bunu üç adımda yapacağız

  1. git rebase branch-A // Synchronises the history with branch-A
  2. git checkout branch-A // Change the current branch to branch-A
  3. git merge branch-B // Merge/take the changes from branch-B to branch-A

İlk olarak Git, hatlar dallanmaya başladıktan sonra (ortak atadan sonra) gerçekleşen A dalındaki tüm taahhütleri "geri alacak". Ancak, elbette, onları atmayacaktır: bunun yerine, bu taahhütleri "geçici olarak kurtarıldı" olarak düşünebilirsiniz.

Resim açıklamasını buraya girin

Daha sonra, entegre etmek istediğimiz B şubesinden taahhütleri uygular. Bu noktada, her iki dal da tamamen aynı görünüyor.

Resim açıklamasını buraya girin

Son adımda, şube-A'daki yeni taahhütler şimdi yeniden uygulanmaktadır - ancak yeni bir pozisyonda, şube-B'deki entegre taahhütlerin üstünde (yeniden temel almaktadır).

Sonuç, düz bir çizgide gelişme olmuş gibi görünüyor. Tüm birleşik değişiklikleri içeren bir birleştirme taahhüdü yerine orijinal taahhüt yapısı korunmuştur.

Resim açıklamasını buraya girin

Son olarak, istenmeyen ve otomatik olarak oluşturulan taahhütler olmadan temiz bir dal dalı-A elde edersiniz .

Not: tarafından müthiş gönderiden alınmıştır git-tower. Dezavantajları arasında rebaseda aynı görevde oku iyidir.


Çok güzel diyagramlar için +1. Her zaman bir git akış örneğini şanssız bir şekilde göstermek istedim.
Mikayil Abdullayev

60

Birleştirmeden / yeniden birleştirmeden önce:

A <- B <- C    [master]
^
 \
  D <- E       [branch]

Sonra git merge master:

A <- B <- C
^         ^
 \         \
  D <- E <- F

Sonra git rebase master:

A <- B <- C <- D' <- E'

(A, B, C, D, E ve F taahhüt edilmiştir)

Bu örnek ve Git hakkında çok daha iyi resimli bilgiler Git Temelleri Eğitimi'nde bulunabilir .



25

Bu cevap Git Flow'un etrafında yoğunlaşmıştır . Tablolar güzel ile üretilmiş olan ASCII Tablosu Jeneratör ve bu harika komutla (ile geçmiş ağaçları Aliased olarak git lg):

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

Tablolar, tarih ağaçlarıyla daha tutarlı olması için ters kronolojik sıradadır. Ayrıca git mergeve git merge --no-ffilk arasındaki farkı da görün (genellikle git merge --no-ffgeçmişinizi gerçeğe daha yakın hale getirmek için kullanmak istiyorsunuz ):

git merge

Komutlar:

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

Komutlar:

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge vs git rebase

İlk nokta: her zaman özellikleri geliştirmekle birleştirin, asla özelliklerden gelişmeyin . Bu Altın Yeniden İskan Kuralının bir sonucudur :

Altın kuralı git rebase, onu asla kamu dallarında kullanmamaktır .

Başka bir deyişle :

Bir yere ittiğiniz hiçbir şeyi asla yeniden pazarlamayın.

Şahsen ekleyeceğim: bir özellik dalı olmadığı sürece VE siz ve ekibiniz sonuçların farkındasınız .

Bu nedenle git mergevs sorusu git rebaseneredeyse sadece özellik dalları için geçerlidir (aşağıdaki örneklerde --no-ffbirleştirme sırasında her zaman kullanılmıştır). Daha iyi bir çözüm olduğundan emin olmadığım için ( bir tartışma var ), sadece her iki komutun nasıl davrandığını da sağlayacağım. Benim durumumda, git rebasedaha güzel bir tarih ağacı ürettiği için kullanmayı tercih ediyorum :)

Özellik dalları arasında

git merge

Komutlar:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Komutlar:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Gönderen developbir özellik dalına

git merge

Komutlar:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git merge --no-ff develop
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Komutlar:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git rebase develop
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Yan notlar

git cherry-pick

Sadece belirli bir taahhüdüne ihtiyacınız git cherry-pickolduğunda, hoş bir çözümdür ( -xseçenek , orijinal taahhüt mesajı gövdesine " (kirazdan alınan ...) " yazan bir satır ekler , bu yüzden onu kullanmak genellikle iyi bir fikirdir - git log <commit_sha1>görmek için o):

Komutlar:

Time           Branch "develop"              Branch "features/foo"                Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git cherry-pick -x <second_commit_sha1>
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Sonuç:

*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

Ben Derek Gourlay daha iyi açıklayabilir emin değilim ... Temelde, git pull --rebaseyerine kullanın git pull:) Makalede eksik olsa da, varsayılan olarak etkinleştirebilirsiniz olmasıdır :

git config --global pull.rebase true

git rerere

Yine, burada güzel açıkladı . Ancak, basitçe, etkinleştirirseniz, aynı çatışmayı artık birkaç kez çözmeniz gerekmeyecek.


15

Pro Git kitap gerçekten iyi bir açıklaması var rebasing sayfa .

Temel olarak bir birleştirme iki taahhüdü alır ve birleştirir.

Bir yeniden taban, ikisinin ortak atalarına gidecek ve değişiklikleri üst üste uygulayacaktır. Bu 'daha temiz' ve daha doğrusal bir tarih sağlar.

Ancak yeniden pazarladığınız zaman, önceki taahhütlerden vazgeçersiniz ve yenilerini yaratırsınız. Bu yüzden asla halka açık bir depoyu yeniden temellendirmemelisiniz. Depo üzerinde çalışan diğer kişiler sizden nefret edecek.

Bu sebepten ötürü neredeyse tamamen birleşiyorum. Şubelerimin% 99'u bu kadar farklı değil, bu yüzden çatışmalar varsa sadece bir veya iki yerde.


1
Birleşmeler taahhütleri birleştirmez - bu tarihin yeniden yazılmasıdır. Rebase bunu yapar.
kellyfj

4

Git rebase tarihin dallanma yollarını daha temiz ve depo yapısını doğrusal hale getirmek için kullanılır.

Ayrıca, oluşturduğunuz dalları gizli tutmak için kullanılır, çünkü değişiklikleri sunucuya yeniden bastırarak ve ittikten sonra, şubenizi silerseniz, üzerinde çalıştığınız şube kanıtı olmayacaktır. Yani şubeniz artık sizin yerel kaygınız.

Rebase yaptıktan sonra, normal bir birleştirme yapıp yapmadığımızı görmek için kullandığımız ekstra bir taahhütten de kurtuluruz.

Ve evet, rebase komutu çalışmanızı rebase sırasında bahsettiğiniz dalın üstüne koyar, usta deyin ve dalınızın ilk taahhüdünü ana dalın doğrudan torunu olarak yaptığından, başarılı bir yeniden tabandan sonra hala birleşme gerekir. . Bu, artık bu daldan ana dala değişiklik getirmek için hızlı bir ileri birleştirme yapabileceğimiz anlamına gelir.


4

Yalnızca bir geliştiriciyseniz , açık bir geçmişe sahip olmak için birleştirme yerine rebase kullanabilirsiniz

resim açıklamasını buraya girin


3

Gerrit'in inceleme ve teslimat entegrasyonu için kullanıldığı büyük ölçekli geliştirmeyle bağlantılı bazı pratik örnekler :

Özellik dalımı yeni bir uzak ustaya yükselttiğimde birleşiyorum. Bu, minimal yükseltme çalışması sağlar ve örneğin gitk'te özellik geliştirme geçmişini takip etmek kolaydır .

git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature

Bir teslimat taahhüdü hazırlarken birleşiyorum.

git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master

Teslimat taahhüdüm herhangi bir nedenden ötürü entegrasyon başarısız olduğunda yeniden temellendiriyorum ve yeni bir uzak ustaya doğru güncellemem gerekiyor.

git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master

3

Birçok kez hangi yeniden tabanın ve birleştirmenin ne olduğu açıklandı, ama ne zaman kullanılmalı?

Rebase'i ne zaman kullanmalısınız?

  • Şubeyi itmediyseniz / başka kimse üzerinde çalışmaz
  • tüm tarihi istiyorsun
  • otomatik olarak oluşturulan tüm "birleştirilmiş .." işleminden kaçınmak istersiniz

Git rebase geçmişi değiştirdikçe. Bu nedenle, başka biri aynı dalda çalışırken / ittiyseniz kullanmamalısınız. Ancak yerel bir şubeniz varsa, daha temiz bir geçmiş tutmak için şubenizi yeniden master'a birleştirmeden önce birleştirme rebase master'ı yapabilirsiniz. Bunu yapmak, ana dalda birleştikten sonra ana dalda bir dal kullandığınız görünmeyecektir - otomatik olarak oluşturulan "birleştirilmiş .." olmadığından geçmiş "temiz" olur, ancak yine de ana dalınızdaki tüm geçmişi otomatik olarak oluşturmadan "birleştirilmiş .." taahhüt eder.

Yine de, git merge feature-branch --ff-onlyözelliğinizi tekrar anaya birleştirirken tek bir taahhüt oluşturan çakışma olmadığından emin olmak için kullanın .Özellik dalının geçmişini alırken üzerinde çalıştığınız her görev için özellik dalları kullanıyorsanız, ancak bir "birleştirilmiş .." taahhüdü kullanmıyorsanız bu ilginçtir.

İkinci bir senaryo, bir daldan ayrılırsanız ve ana dalda nelerin değiştiğini bilmek istiyorsanız. Rebase size her bir taahhüdü içerdiği için bilgi verir.

Birleştirme ne zaman kullanılmalıdır?

  • Şubeyi ittiğinizde / diğerleri de üzerinde çalışıyor
  • tam geçmişe ihtiyacınız yok
  • sadece birleştirme senin için yeterince iyi

Ana dalınızdaki bir özellik dalının tüm geçmişine ihtiyacınız olmadığında veya olmasını istediğinizde veya başkaları aynı dalda çalışıyorsa / siz onu ittiniz. Hala geçmişe sahip olmak istiyorsanız, özellik dalını master ile birleştirmeden önce master'ı özellik dalıyla birleştirmeniz yeterlidir. Bu, ana öğenizdeki özellik dalının geçmişine sahip olduğunuz hızlı ileri bir birleştirme ile sonuçlanır (ana bilgisayarı birleştirdiğiniz için özellik dalınızdaki birleştirme taahhüdü dahil).


-4

Ne zaman kullanırım git rebase? Neredeyse asla, çünkü tarihi yeniden yazıyor. git mergeneredeyse her zaman tercih edilen seçimdir, çünkü projenizde gerçekte ne olduğuna saygı duyar.


1
@benjaminhull Teşekkürler! - Umarım cevabım gerçeğe dayalıdır. IMHO'nun bu tür şeylerde çok az yeri vardır: gerçek tarihinizi kaybetmenin daha sonra hayatı zorlaştırdığı bir gerçektir .
Marnen Laibow-Koser

1
Katılıyorum. Birleştirme asla bozuk geçmişe vb.
Yol açmayacaktır (
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.