Git rebase vs. Git merge kullanılması ne zaman önerilir?
Başarılı bir tekrardan sonra hala birleştirmem gerekiyor mu?
Git rebase vs. Git merge kullanılması ne zaman önerilir?
Başarılı bir tekrardan sonra hala birleştirmem gerekiyor mu?
Yanıtlar:
Peki ne zaman birini kullanıyorsun?
init
yeni bir repo, add
dosya 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 master
ve 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.
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 master
ve 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.
but this way a new dummy commit is added, if you want to avoid spaghetti-history
- nasıl kötü?
Sean Schofield
bir 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. "
merge
, rebase
, fast-forward
vs.) yönlendirilmiş Mercury grafik belirli manipülasyonlara kastediyoruz. Akıldaki bu zihinsel model ile akıl yürütmeleri daha kolay hale gelir.
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 B
birleş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 B
hı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 B
kararlı 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 B
bir 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ı
biz rebasing olsun:
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 master
size yapılan hareketin kaydedilmesini korumak istiyorsanız sizinnew-feature
dalı).
Yani:
master
.Herhangi bir şüpheniz varsa, birleştirme kullanın.
Rebase ve birleştirme arasındaki tek farklar:
Bu nedenle kısa cevap, geçmişinizin nasıl görünmesini istediğinize göre yeniden taban oluşturmak veya birleştirmek .
Hangi işlemi kullanacağınızı seçerken dikkate almanız gereken birkaç faktör vardır.
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.
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.
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.
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.
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 --rebase
tüm çekimlerde) rebase kullanılmasını önerir .
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.
İ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.
Eğer takma nasıl rm
üzere rm -rf
"Zaman tasarrufu" o zaman belki Rebase size göre.
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.
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.
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:
Buna karşılık, bir konu dalını ana birime birleştirmek:
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.
git merge
, --no-ff
birleştirme işlemi yapmaya zorlayan seçeneği destekler .
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:
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.
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.
Bununla birlikte, birçok durumda, her iki dal ayrı ayrı ilerledi.
Bir entegrasyon yapmak için Git, aralarındaki farkları içeren yeni bir taahhüt oluşturmak zorunda kalacak - birleştirme taahhüdü.
İ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ı.
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.
Bunu üç adımda yapacağız
git rebase branch-A // Synchronises the history with branch-A
git checkout branch-A // Change the current branch to branch-A
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.
Daha sonra, entegre etmek istediğimiz B şubesinden taahhütleri uygular. Bu noktada, her iki dal da tamamen aynı görünüyor.
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.
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 rebase
da aynı görevde oku iyidir.
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 .
Bu cümleyi alır:
Genel olarak, her iki dünyanın en iyisini elde etmenin yolu, hikayenizi temizlemek için onları itmeden önce yaptığınız, ancak henüz paylaşmadığınız yerel değişiklikleri yeniden birleştirmektir, ancak hiçbir yere ittiğiniz hiçbir şeyi yeniden temellendirmeyin .
Kaynak: 3.6 Git Dallanma - Yeniden Düzenleme, Yeniden Düzenleme ve Birleştirme
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 merge
ve git merge --no-ff
ilk arasındaki farkı da görün (genellikle git merge --no-ff
geç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 .
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 merge
vs sorusu git rebase
neredeyse sadece özellik dalları için geçerlidir (aşağıdaki örneklerde --no-ff
birleş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 rebase
daha güzel bir tarih ağacı ürettiği için kullanmayı tercih ediyorum :)
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
develop
bir özellik dalınagit 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
git cherry-pick
Sadece belirli bir taahhüdüne ihtiyacınız git cherry-pick
olduğunda, hoş bir çözümdür ( -x
seç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 --rebase
yerine 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.
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.
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.
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
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?
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?
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).
Ne zaman kullanırım git rebase
? Neredeyse asla, çünkü tarihi yeniden yazıyor. git merge
neredeyse her zaman tercih edilen seçimdir, çünkü projenizde gerçekte ne olduğuna saygı duyar.