GIT MERGE VE REBASE FARKI

Veri Akademi7 dk okuma
Merge commit ile çatallı history yapısının yanına rebase ile düzleştirilmiş doğrusal commit zincirini koyan karşılaştırma diyagramı

Yaygın bir yanlış var: "Merge de rebase de aynı işi yapar, sadece tercih meselesi." Oysa ikisi aynı sonucu vermez. Merge commit geçmişini olduğu gibi bırakır ve birleşmeyi gösteren yeni bir commit ekler; rebase ise commit'leri yeniden yazar ve geçmişi düzleştirir. Bu yapısal fark, public branch'te rebase yapmanın neden takım arkadaşlarınızın deposunu bozabileceğini ve neden bazı projelerin "rebase yasak" kuralı koyduğunu açıklar. Farkı net görmeden seçim yapmak, code review akışınızı ve git log'unuzu uzun vadede ciddi şekilde etkiler.

1. Merge ve rebase neden aynı sonucu vermez

Yüzeyde her ikisi de "iki branch'i birleştirmek" işini yapar. Fakat sonuçta ortaya çıkan commit grafiği bambaşkadır. Merge yapıldığında Git, iki ata commit'i olan yeni bir "merge commit" üretir; branch'lerin ayrılıp tekrar birleştiği nokta history'de görünür kalır. Rebase yapıldığında ise feature branch'inizdeki commit'ler, hedef branch'in en güncel commit'inin üstüne tek tek yeniden uygulanır. Aynı içerikte ama farklı SHA değerine sahip yeni commit'ler oluşur.

Sonuç şudur: rebase sonrası eski commit'leriniz teknik olarak başka commit'lerdir. Aynı değişikliği taşıyorlar ama Git nesne deposunda artık farklı kimliklere sahipler. Bu, sadece lokalde çalıştığınız bir branch için sorun değildir; ancak başkalarının da o commit'leri çekmiş olduğu durumda kaos yaratır.

2. Git merge nasıl çalışır

Bir feature branch'i main'e merge ettiğinizde Git iki yoldan birini seçer:

  • Fast-forward: main, feature ayrıldığından beri hiç ilerlemediyse Git sadece main pointer'ını ileri taşır. Yeni bir commit oluşmaz, history düz görünür.
  • Three-way merge: her iki branch de yeni commit aldıysa Git ortak ata commit'i bulur, üç noktadan içeriği birleştirir ve iki ataya bağlanan yeni bir merge commit yaratır.

Three-way merge'in görünür dezavantajı history'nin "diamond" şekline girmesidir. Çok sayıda paralel branch'in birleştiği projelerde grafik karmaşıklaşır. Avantajı ise hiçbir commit'in kaybolmaması ve her birleşmenin açıkça izlenebilir olmasıdır.

3. Git rebase nasıl çalışır

Rebase, feature branch'inizdeki commit'leri "söker" ve hedef branch'in tepesine sırayla yeniden uygular. Her commit için tek tek cherry-pick yapılıyor gibidir. Sonuçta history doğrusal kalır; merge commit'i yoktur, sanki feature branch baştan main'in son halinden çıkmış gibi görünür.

Interactive rebase (git rebase -i) daha güçlüdür: commit'leri birleştirebilir (squash), yeniden sıralayabilir, mesajlarını düzenleyebilir veya silebilirsiniz. Pull request açmadan önce commit geçmişini temizlemek için sık kullanılan bir yöntemdir. Komutun davranışı ve ileri seçenekleri için resmi dokümantasyonu incelemek faydalıdır.

İki paralel branch'in merge commit ile birleştiği three-way merge ve fast-forward modunda main ileri kaydığı akış diyagramı

4. History şekli neden önemlidir

Bazı projeler "her zaman merge" der, bazıları "her zaman rebase". İki yaklaşımın da gerekçesi history'nin nasıl okunmasını istediğinizle ilgilidir:

  • Merge tarafı: "Gerçeği görmek istiyoruz. Hangi branch ne zaman birleşmiş, kim hangi feature'u nasıl entegre etmiş, hepsi grafikten okunsun."
  • Rebase tarafı: "git log okunabilir olsun. Linear history bisect ile bug aramada kolaylık verir, gereksiz merge commit'leri kalabalık yapmaz."

Her iki yaklaşım da geçerlidir; karar genelde projenin büyüklüğü, paralel branch sayısı ve code review akışıyla şekillenir. Git komutlarına yeni başlıyorsanız temel kavramları toparlamak için git eğitimi içeriğinden yararlanabilirsiniz.

5. Public branch'te rebase neden risklidir

Altın kural: Başkasının çektiği bir branch'i rebase etme. Sebep şudur: rebase commit SHA'larını değiştirir. Siz paylaşılan bir branch üzerinde rebase yaptıysanız ve git push --force ile gönderdiyseniz, aynı branch'i daha önce pull'lamış olan herkes artık eski-yeni karışık iki paralel history ile karşılaşır.

Pratikte yaşananlar şöyle gelişir:

  1. Siz force push ile rebase edilmiş branch'i remote'a gönderirsiniz.
  2. Bir başkası eski commit'lerin üstüne yeni iş yapmıştır.
  3. O kişi pull yaptığında Git, yeni ve eski commit'leri merge etmeye çalışır. Aynı değişiklik iki defa history'de görünür ve conflict'ler saatlerce uğraştırır.

Bu yüzden çoğu projenin yazılı kuralı şudur: lokal branch'inde istediğin kadar rebase yap, ama paylaşılan branch'e (özellikle main, develop, release) asla rebase ile force push etme.

6. Conflict çözümünde fark

Merge sırasında conflict olursa tek bir noktada çözersiniz: birleşmenin yapıldığı an. Rebase sırasında ise her bir commit'in yeniden uygulanması ayrı bir adımdır; aynı dosya üzerinde birden fazla commit varsa aynı conflict'i defalarca çözmek zorunda kalabilirsiniz. git rerere tekrar eden çözümleri hatırlayarak bu acıyı bir nebze hafifletir ama tamamen ortadan kaldırmaz.

Pratik sonuç: çok sayıda commit'i olan ve hedef branch ile arası açılmış bir feature dalını rebase etmek yorucu olabilir. Bu senaryoda merge daha az acı veren seçenektir, çünkü tüm birikmiş conflict'i tek seferde çözersiniz.

7. Hangi durumda hangisini seçmelisiniz

Tek bir doğru cevap yoktur ama pratik yönlendirici kurallar var:

  • Lokal feature branch'ini main ile güncel tutmak: rebase tercih edilir, history temiz kalır.
  • PR açmadan önce commit'leri temizlemek: interactive rebase ile squash ve reword idealdir.
  • PR'ı paylaşılan main'e almak: merge (veya squash merge) güvenlidir, force push gerekmez.
  • Birden fazla kişinin çalıştığı feature branch: rebase YAPMAYIN; merge ile senkronize edin.
  • Production hotfix: küçük ve direkt — fast-forward merge en sade çözümdür.
Rebase sırasında commit'lerin sökülüp hedef branch tepesine yeni SHA değerleriyle yeniden uygulandığı timeline diyagramı

Sonuçta merge ve rebase rakip değil, farklı amaçlara hizmet eden iki araçtır. Merge tarihi olduğu gibi korur, rebase okunaklı kılar. Yanlış olan, ikisini birbirinin yerine sanmak ve paylaşılan branch'te rebase ile force push ederek başkalarının deposunu bozmaktır. Branch'i kimin kullandığını, history'den ne beklediğinizi ve takım kurallarınızı bilince doğru tercih kendiliğinden netleşir.

Sıkça Sorulan Sorular

Git merge mi rebase mi daha iyidir?

Mutlak bir cevap yoktur. Merge history'yi olduğu gibi korur ve paylaşılan branch'lerde güvenlidir. Rebase ise linear ve okunaklı bir history bırakır, lokal branch'leri güncel tutmak ve PR öncesi commit'leri toparlamak için idealdir. Karar kullanım senaryosuna göre değişir.

Rebase yapınca commit'ler kaybolur mu?

Hayır, içerik kaybolmaz; ancak commit SHA'ları değişir. Eski commit'ler reflog'da bir süre kalır ve gerekirse oradan kurtarılabilir. Yine de force push sonrası başkalarının kopyasındaki eski referanslar tutarsızlık yaratabilir, bu yüzden dikkatli olunmalıdır.

Public branch'te rebase neden yasak?

Rebase commit'lerin SHA'larını değiştirdiği için aynı branch'i çekmiş diğer kişilerde eski-yeni paralel history oluşur. Sonraki pull işlemlerinde aynı değişiklik tekrar tekrar görünür ve conflict zinciri başlar. Bu yüzden main, develop ve release gibi paylaşılan dallarda rebase yapılmaz.

Fast-forward merge nedir?

Hedef branch, kaynak branch ayrıldığından beri hiç ilerlemediyse Git ayrı bir merge commit oluşturmadan sadece branch pointer'ını ileri kaydırır. Buna fast-forward denir. History düz görünür, ayrı bir birleşme noktası bırakmaz; küçük ve hızlı entegrasyonlar için sade bir yöntemdir.

Interactive rebase ne işe yarar?

git rebase -i komutu, branch'inizdeki commit'leri yeniden sıralama, birleştirme (squash), mesajlarını düzenleme veya tamamen silme imkânı verir. Genellikle pull request açmadan önce dağınık commit geçmişini sade ve anlamlı bir akışa dönüştürmek için kullanılır.

Git rebase sırasında conflict çıkarsa ne yapılır?

Çakışan dosyalar elle çözülür, ardından git add ile işaretlenir ve git rebase --continue ile devam edilir. Eğer aynı conflict art arda birkaç commit'te tekrar ediyorsa git rerere etkinleştirilebilir. Süreçten vazgeçmek isterseniz git rebase --abort başlangıç durumuna döndürür.

Pull request'lerde squash merge mi normal merge mi tercih edilmeli?

Squash merge tüm PR commit'lerini tek bir commit'e indirir; main history kısa ve okunaklı kalır. Normal merge ise PR'daki tüm commit'leri ve merge commit'ini olduğu gibi tutar. Detaylı geçmiş isteyen projeler normal merge'i, sade log isteyenler squash merge'i seçer.

Rebase sonrası push neden reddediliyor?

Rebase commit SHA'larını değiştirdiği için remote ile lokal history aynı geçmişi paylaşmaz. Git, normal push'u veri kaybı riski olarak görüp reddeder. Yalnızca kendi kullandığınız bir branch ise git push --force-with-lease ile gönderilebilir; paylaşılan branch'te bu yapılmaz.