- Github
Git Merge ve Rebase Nedir? Farkları ve Profesyonel Kullanım Rehberi
Git'te branch birleştirme, commit geçmişini düzenleme, conflict çözme ve ekip çalışmalarında merge ile rebase kullanmayı öğrenin.
Zeynep Baş9 dk okuma
1. Git Merge ve Rebase Nedir?
Farklı branch'lerdeki çalışmaları bir araya getirmek
Git, yazılım projelerindeki değişiklikleri takip etmeyi sağlayan bir sürüm kontrol sistemidir. Ekip çalışmalarında geliştiriciler genellikle main gibi ana bir branch üzerinden yeni branch'ler oluşturarak birbirlerinden bağımsız çalışırlar. Bu çalışmaların daha sonra bir araya getirilmesi gerekir.
Git merge, iki branch'in geçmişini birleştirir. Gerekli olduğunda bir merge commit'i oluşturur ve her iki branch'te yapılan değişikliklerin ortak geçmişte korunmasını sağlar.
Git rebase ise seçilen branch'teki commit'leri başka bir branch'in tabanının üzerine yeniden uygular. Böylece commit geçmişi daha doğrusal görünebilir. Bu işlem yeni commit kimlikleri oluşturabileceği için mevcut geçmişi değiştirir.
Her iki yöntem de farklı branch'lerdeki değişiklikleri bir araya getirmeye yardımcı olabilir. Ancak aynı işlemi farklı şekilde yazmaktan ibaret değildirler. Hangi yöntemin kullanılacağı, amaçlanan sonuca ve takımın Git iş akışına bağlıdır.
2. Git Branch Mantığını Anlamak
Main, feature branch ve commit ilişkisi
Bir branch, Git geçmişindeki belirli bir commit'i işaret eden ve yeni commit'lerle ilerleyebilen bir referanstır. Geliştiriciler yeni özellikler eklerken veya hata düzeltirken ayrı branch'ler kullanarak main dalındaki çalışmayı koruyabilirler.
Örneğin bir geliştirici feature/login, diğeri feature/dashboard branch'inde çalışabilir. İki branch de başlangıçta main'in aynı commit'inden oluşturulmuş olabilir. Geliştiriciler kendi değişikliklerini commit ettikçe branch'ler farklı yönlerde ilerler.
Bu çalışmalar bir araya getirilirken merge veya rebase kullanılabilir. Ancak rebase'in her iki branch'i birleştirmek için otomatik bir çözüm olmadığını anlamak önemlidir. Rebase, mevcut branch'teki commit'leri seçilen tabanın üzerine yeniden uygularken merge, iki geçmişi birleştirir.
git branch -a yerel ve uzak branch referanslarını listeler. git switch -c yeni bir branch oluşturup ona geçer. git status ise hangi branch'te olduğunu ve çalışma alanındaki değişiklikleri gösterir.
3. Git Merge Nasıl Çalışır?
İki branch'in geçmişini birleştirmek
Merge, bir branch'teki değişiklikleri mevcut branch ile birleştirmek istediğinde kullanılır. Önce hedef branch'e geçilir, ardından birleştirilmek istenen branch belirtilir.
Bu örnekte feature/dashboard branch'indeki uzak değişiklikler feature/login branch'ine birleştirilmeye çalışılır. git fetch origin uzak depodaki bilgileri günceller ancak çalışma dosyalarını birleştirmez. Birleştirme işlemini gerçekleştiren komut git merge'dür.
Merge sırasında mevcut geçmişe göre fast-forward yapılabilir veya iki dalı birleştiren yeni bir merge commit'i oluşturulabilir. Bu davranış branch'lerin commit ilişkisine ve kullanılan merge seçeneklerine bağlıdır.
Merge, arkadaşının kodunu kendi branch'ine almak için kullanılabilir. Ancak kaynak branch'teki yalnızca frontend dosyalarını seçmez; branch'teki bütün ilgili değişiklikleri birleştirmeye çalışır. Yalnızca belirli dosyaları almak istiyorsan farklı Git işlemlerine ihtiyaç duyabilirsin.
Birleştirme öncesinde git status ile çalışma alanını kontrol etmek önemlidir. Özellikle commit edilmemiş değişiklikler varsa bunları commit etmek veya uygun şekilde stash etmek, işlemin daha kontrollü yürütülmesini sağlar.
4. Git Rebase Nasıl Çalışır?
Kendi commit'lerini güncel bir tabanın üzerine taşımak
Rebase'in sık kullanılan amaçlarından biri, bir feature branch'i main dalında yapılan yeni değişikliklerle güncel tutmaktır. Böylece geliştirici, kendi commit'lerini güncel main geçmişinin üzerine yeniden uygulayabilir.
Bu komutlar önce uzak depo bilgilerini getirir, sonra feature/login branch'ine geçer ve bu branch'teki main tabanından sonra gelen commit'leri origin/main üzerine yeniden uygular.
Örneğin sen main'in M1 commit'inden başlayıp A1 commit'ini oluşturdun. Bu sırada main, M2 commit'iyle ilerledi. Rebase sonrasında geçmiş yaklaşık olarak M1, M2 ve A1' şeklinde görünür. A1', eski commit'in yeni taban üzerine yeniden uygulanmış hâlidir ve farklı bir commit hash'ine sahip olabilir.
Rebase, branch'in main'in önüne geçmesini sağlamak amacıyla kullanılmaz. Amaç, kendi değişikliklerini güncel tabanın üzerine yerleştirmek ve daha doğrusal bir geçmiş elde etmektir.
Rebase'in her projede zorunlu olmadığını unutmamak gerekir. Bazı takımlar feature branch'lerini main ile merge ederek günceller; bazıları rebase tercih eder. Çalışılan projenin kuralları ve takımın ortak yaklaşımı dikkate alınmalıdır.
5. Merge ve Rebase Arasındaki Temel Farklar
Hangi işlem ne zaman tercih edilir?
Merge ve rebase arasındaki en önemli fark, commit geçmişini nasıl ele aldıklarıdır. Merge iki dalın geçmişini birleştirirken rebase mevcut commit'leri yeni bir tabanın üzerine yeniden uygular.
Merge, geçmişte dallanma ve birleşme ilişkisini görünür tutabilir. Rebase ise çoğunlukla daha doğrusal bir commit geçmişi oluşturur. Ancak doğrusal geçmiş her zaman daha doğru anlamına gelmez; bazı ekipler gerçek birleştirme noktalarının görünür kalmasını tercih eder.
Merge genellikle mevcut commit kimliklerini korur. Rebase ise yeniden uygulanan commit'lerin kimliklerini değiştirir. Bu nedenle başkalarının da kullandığı bir branch üzerinde rebase yapmak, ekip üyelerinin geçmişini senkronize etmesini zorlaştırabilir.
Merge kullanmak çatışmaları tamamen ortadan kaldırmaz. Rebase de conflict çıkmasını önlemez. Her iki işlemde de aynı dosyanın aynı bölümleri farklı şekilde değiştirilmişse manuel çözüm gerekebilir.
Bir yöntemin diğerinden her koşulda daha iyi olduğunu söylemek doğru değildir. Karar verirken commit geçmişinin okunabilirliği, branch'in paylaşılıp paylaşılmadığı ve takımın workflow'u değerlendirilmelidir.
6. Merge ve Rebase Conflict Nasıl Çözülür?
Çakışan kodları düzenlemek ve işleme devam etmek
Conflict, Git'in farklı değişiklikleri otomatik olarak birleştiremediği durumlarda ortaya çıkar. Örneğin iki geliştirici aynı dosyanın aynı satırını farklı biçimde değiştirmiş olabilir. Git bu durumda hangi sonucun doğru olduğuna kendi başına karar veremez.
Çatışma yaşandığında önce git status komutuyla hangi dosyaların etkilendiği kontrol edilir. Ardından dosya açılır ve Git'in eklediği çatışma işaretleri incelenir.
Bu işaretler dosyanın hangi bölümlerinin çakıştığını gösterir. Geliştirici doğru kodu belirleyip dosyayı düzenlemeli ve tüm çatışma işaretlerini kaldırmalıdır. Hangi değişikliğin doğru olduğu uygulamanın gereksinimlerine göre belirlenmelidir.
Merge sırasında dosyalar düzenlenip stage alanına eklendikten sonra merge tamamlanabilir.
Rebase sırasında da çatışmalı dosyalar düzenlenir ve stage alanına eklenir. Ancak devam etmek için git rebase --continue kullanılır.
Birden fazla commit çatışma çıkarırsa rebase sırasında aynı çözüm süreci tekrarlanabilir. İşlemi iptal etmek gerektiğinde merge için git merge --abort, rebase için git rebase --abort kullanılabilir. İşlem öncesindeki commit edilmemiş değişiklikleri korumak için başlamadan önce çalışma alanını kontrol etmek gerekir.
7. Ekip Çalışmasında Merge mi Rebase mi?
Arkadaşının kodunu almak ve main dalını güncel tutmak
Diyelim ki sen feature/login, takım arkadaşın feature/dashboard branch'inde çalışıyor. Arkadaşının değişikliklerini kendi branch'ine entegre etmek istiyorsan merge kullanılabilir.
Kendi branch'ini güncel main üzerine taşımak istiyorsan rebase tercih edilebilir.
Bu örnekler yaygın kullanım biçimlerini gösterir; kesin kurallar değildir. Arkadaşının branch'ini kendi branch'ine rebase etmek de teknik olarak mümkündür. Ancak bunun uygun olup olmadığı commit geçmişine, branch'in paylaşılmış olmasına ve takımın tercihine bağlıdır.
Profesyonel ekiplerde genellikle her özellik için ayrı branch açılır, değişiklikler uzak depoya gönderilir ve Pull Request üzerinden code review yapılır. PR onaylandıktan sonra kodlar main dalına, takımın belirlediği merge, squash veya rebase yöntemiyle birleştirilebilir.
Bir ekip rebase kullanıyorsa bile her geliştiricinin ortak branch'lerin geçmişini istediği gibi değiştirmesi beklenmez. Paylaşılmış commit'leri yeniden yazmadan önce takım kurallarını kontrol etmek gerekir.
8. Pull Request ve Code Review Sürecinde Rebase
PR öncesinde branch'i güncel tutmak
Pull Request, bir branch'teki değişikliklerin başka bir branch'e alınması için inceleme ve onay süreci başlatır. GitHub üzerinde geliştirici kendi branch'ini push ettikten sonra genellikle main hedefli bir PR açar.
PR açıkken main dalına yeni commit'ler eklenebilir. Projenin kurallarına göre geliştiriciden branch'ini güncellemesi istenebilir. Bu aşamada git rebase origin/main veya git merge origin/main seçeneklerinden biri kullanılabilir.
Rebase ile güncellenen ve daha önce uzak depoya gönderilmiş bir branch'i push etmek, geçmiş yeniden yazıldığı için normal push işleminin reddedilmesine neden olabilir. Yalnızca branch sana aitse ve takım politikası izin veriyorsa git push --force-with-lease düşünülebilir. Bu komut da uzak geçmişi değiştirebilir; ortak branch'lerde gelişigüzel kullanılmamalıdır.
Bazı takımlar PR birleştirilirken Create a merge commit, Squash and merge veya Rebase and merge seçeneklerinden birini kullanır. Bu seçenekler GitHub'ın PR birleştirme yöntemleridir ve geliştiricinin yerel branch'inde rebase yapmasıyla aynı işlem değildir.
Code review sırasında geliştiriciden değişiklik istenirse aynı branch'e yeni commit'ler eklenip push edilebilir. Böylece PR güncellenir ve yeniden incelemeye alınabilir.
9. Son Commit'i Geri Alma: Reset, Amend ve Revert
Her Git işlemi farklı bir amaca hizmet eder
Son commit ile ilgili işlem yapmak istediğinde önce amacını belirlemelisin. Commit'i geçmişten çıkarıp değişiklikleri korumak, commit mesajını düzeltmek ve commit'in etkisini geri almak farklı ihtiyaçlardır.
git reset --soft HEAD~1, yerel branch'i bir önceki commit'e taşır ve geri alınan commit'in değişikliklerini staged durumda bırakır. Bu yöntem, henüz paylaşılmamış bir commit'i geri alıp yeniden oluşturmak istediğinde kullanılabilir.
git commit --amend, son commit'i yeni bir commit ile değiştirir. Mesajı düzeltmek veya staged değişiklikleri son commit'e eklemek için kullanılabilir.
git revert HEAD ise mevcut commit'in etkilerini geri alan yeni bir commit oluşturur. Daha önce paylaşılmış geçmişi doğrudan yeniden yazmadan bir değişikliği geri almak gerektiğinde genellikle uygun bir seçenektir.
Reset ve amend sonrasında commit geçmişi değişebileceğinden, bu işlemler daha önce push edilmiş branch'lerde dikkatle kullanılmalıdır. Ortak bir branch'te commit silmek veya geçmişi yeniden yazmak yerine revert kullanmak çoğu zaman daha güvenlidir.
10. Git Merge ve Rebase İçin Örnek İş Akışı
Bir feature branch'i baştan sona yönetmek
Yeni bir özellik geliştirirken önce main dalının güncel olduğundan emin olabilir, ardından ayrı bir branch açabilirsin. Takımın mevcut kurallarına göre branch'in güncel tutulması ve PR'ın birleştirilmesi sağlanır.
Kodunu tamamladıktan sonra değişikliklerini commit edip uzak depoya gönderebilirsin.
Main dalı ilerlediyse ve takım rebase kullanıyorsa kendi branch'ini güncelleyebilirsin.
Çatışmalar varsa çözülür, testler çalıştırılır ve gerekiyorsa branch yeniden push edilir. Ardından GitHub'da Pull Request açılır, code review tamamlanır ve kodlar ekip politikasına göre main dalına birleştirilir.
Bu örnek, her şirketin birebir aynı şekilde çalıştığı anlamına gelmez. Bazı ekipler rebase yerine merge kullanır, bazıları squash merge tercih eder veya main dalına doğrudan push yapılmasını engelleyen koruma kuralları uygular.
11. Hangi Durumda Hangi Komut Kullanılır?
Günlük geliştirme için kısa bir karar rehberi
Yeni branch oluşturmak için git switch -c feature/branch-name kullanabilirsin. Branch'leri listelemek için git branch -a, çalışma alanını kontrol etmek için git status komutları yararlıdır.
Arkadaşının branch'indeki değişiklikleri kendi branch'ine birleştirmek istediğinde git merge tercih edilebilir. Kendi commit'lerini güncel main üzerine yeniden uygulamak istediğinde git rebase kullanılabilir.
Son commit'i değişiklikleri staged tutarak geri almak için git reset --soft HEAD~1, son commit mesajını düzeltmek için git commit --amend, paylaşılmış bir değişikliğin etkisini geri almak için git revert HEAD kullanılabilir.
Merge conflict çözüldükten sonra git merge --continue, rebase conflict çözüldükten sonra git rebase --continue kullanılır. İşlemi iptal etmek için sırasıyla git merge --abort ve git rebase --abort tercih edilir.
Komutları ezberlemekten daha önemlisi, hangi branch'te olduğunu, hangi commit'leri değiştireceğini ve işlemin paylaşılan geçmişi etkileyip etkilemeyeceğini anlamaktır.
12. Sonuç: Önemli Olan Doğru Workflow'u Seçmek
Git komutlarını amacına göre kullanmak
Git merge ve git rebase, farklı branch'lerdeki değişiklikleri yönetmenin iki önemli yoludur. Merge geçmişi birleştirirken rebase commit'leri başka bir tabanın üzerine yeniden uygular. Bu temel farkı anlamak, ekip çalışmasında doğru karar vermeyi kolaylaştırır.
Merge genellikle arkadaşının değişikliklerini kendi branch'ine entegre etmek veya branch geçmişindeki birleşme noktalarını korumak için uygundur. Rebase ise kendi branch'ini güncel main üzerine taşımak ve daha doğrusal bir geçmiş oluşturmak için tercih edilebilir.
Her iki yöntemde de conflict yaşanabilir. Dosyaları dikkatle düzenlemek, testleri çalıştırmak ve paylaşılmış commit geçmişini korumak gerekir. Özellikle rebase ve reset gibi geçmişi değiştirebilen işlemler, ortak branch'lerde takım kuralları dikkate alınarak kullanılmalıdır.
Profesyonel Git kullanımında amaç yalnızca kodu birleştirmek değildir. Aynı zamanda değişiklikleri izlenebilir, incelenebilir ve güvenli şekilde entegre etmektir. Branch yönetimi, commit mesajları, Pull Request, code review ve uygun birleştirme yöntemi birlikte kullanıldığında ekip çalışması daha düzenli hâle gelir.