Branch Merge / Merge Commit
Git bize yaptığımız değişiklikleri ayırmamıza, gruplamamıza, düzenlememize, geriye almamıza, yani kısaca yönetmemize olanak sağlayan bir araç. Fakat bazen projemizde, veya repository'mizde geldiğimiz noktada iki ayrı değişikliği birleştirmeye ihtiyaç duyabiliyoruz. Bu değişikliklerimizi yönetmek için kullandığımız araç, git aynı zamanda bu değişiklikleri bir arada toplamamıza, veya birleştirmemize de olanak sağlıyor.
Yukarıya ek olarak geçtiğimiz sayfalarda bir commit'in en az bir parent commit'i olması gerektiğinden bahsetmiştik. Bunun üzerine git commit komutu ile yeni bir commit attığımız zaman oluşan commit'in bir parent commit'e baktığını ve bu parent commit'i ile olan ilişkisini ortaya koymuştuk. En az bir parent commit diyerek bir commit'in birden çok parent commit'e de aynı anda bakabildiğini de ima ediyoruz. Eğer ki git commit ile atılan commitler sadece 1 parent'e bakabiliyorsa, o halde birden çok parent'ı olabilen başka bir commit atma yönteminin olması gerekiyor. Burada git'in henüz değinmediğimiz bir operasyonundan bahsetmeye başlayabiliriz.
Git bize iki veya daha fazla commit dalını, yani iki branch'i tek bir noktada toplamamıza merge komutu ile imkan tanıyor. Bu sayede birbirinden ayrılmış iki branch'i tekrar bir araya getirebiliyorsunuz.
Terminoloji
Merge Türkçede birleştirmek, bir araya karıştırmak anlamına gelir. Git bağlamında da anlamı değişmez.
Bu merge operasyonunu önceki sayfalarda üzerinde çalıştığımız repository'miz üzerinde gerçekleştirelim. main branch'imize geçip repository'mizde yeni bir dosya oluşturup commit atalım. Hemen ardından da commit'imizin yaptığı değişikliği gösterelim. Bu değişikliği göstermek için git show komutunu yeni oluşan commit'in hash'i ile birlikte kullanacağız.
$ git checkout main
Switched to branch 'main'
$ echo "Lorem ipsum" > test-2.txt
$ git add test-2.txt
$ git commit -m "test-2.txt dosyasini ekledim"
[main 9a63d64] test-2.txt dosyasini ekledim
1 file changed, 1 insertion(+)
create mode 100644 test-2.txt
$ git show 9a63d64
commit 9a63d6499f568868f73613412f881a770f33342d (HEAD -> main)
Author: <username> <email>
Date: Fri May 2 21:49:15 2025 +0200
test-2.txt dosyasini ekledim
diff --git a/test-2.txt b/test-2.txt
new file mode 100644
index 0000000..3be11c6
--- /dev/null
+++ b/test-2.txt
@@ -0,0 +1 @@
+Lorem ipsum
Şimdi repository'mizin log'una bakalım. Bu sefer --all bayrağını da komutumuza ekleyelim. Bu bayrak ile sadece mevcut branch'in değil bütün repository'nin log'unu görebiliriz.
$ git log --graph --parents --oneline --all
* 9a63d64 777f68a (HEAD -> main) test-2.txt dosyasini ekledim
| * dc2243f 777f68a (yeni-branch-2, yeni-branch) yeni-branch icin ilk commitimi atiyorum
|/
* 777f68a 95e7356 Dosyaya Merhaba Dunya ekledim
* 95e7356 Ilk commit
Buradan anlaşılacağı üzere 777f68a commit'inden başlayarak dallanan 2 ayrı değişiklik zincirimiz var. Biri main branch, diğeri ise yeni-branch ismindeki branch.
Terminoloji
Bu noktada repository'mizde 777f68a commit'i main ve yeni-branch branch'lerinin common ancestor'u, yani ortak atası oluyor.
yeni-branch ismindeki branch'i main branch'e birleştirerek aslında o dalda yapılmış olan değişiklikleri, yani main branch'te bulunmayıp yeni-branch'te bulunan commit'leri main branch'ine de almak istediğimizi varsayalım. Bu birbirinden farklı yönlere dallanmış iki branch'i bir araya getirmek için merge komutunu kullanabiliriz.
Text editoru
Çalıştıracağımız merge komutu bizden commit mesajını düzenlememizi isteyecek. Bu noktada git'in varsayılan olarak kullandığı vi isimli modal text editor açılacaktır. Fakat birçoğumuz buna aşina olmadığı için, bu komutu çalıştırmadan önce sizin git'in kullanacağı text editorunu vscode veya idea olarak değiştirmenizi tavsiye ederim. Bunu aşağıdaki komutlardan birini çalıştırarak sağlayabilirsiniz.
$ git config --global core.editor "code --wait" # vscode icin
$ git config --global core.editor "idea --wait" # JetBrains IntelliJ icin
Merge Branch'ları
Burada yeni-branch isimli branch'i main isimli branch'e merge ediyoruz. Eğer ki merge başarılı olursa main branch'inin baktığı commit güncellenirken yeni-branch isimli branch'de hiçbir değişiklik meydana gelmeyecektir.
$ git merge yeni-branch
Merge made by the 'ort' strategy.
test.txt | 1 +
1 file changed, 1 insertion(+)
Bunu çalıştırdıktan sonra karşınıza açılan text editoru kaydedip çıkarak merge işlemini tamamlayabilirsiniz. Şimdi ise repository'mizin son haline bakalım.
$ git log --graph --parents --oneline --all
* b5b6c09 9a63d64 dc2243f (HEAD -> main) Merge branch 'yeni-branch'
|\
| * dc2243f 777f68a (yeni-branch-2, yeni-branch) yeni-branch icin ilk commitimi atiyorum
* | 9a63d64 777f68a test-2.txt dosyasini ekledim
|/
* 777f68a 95e7356 Dosyaya Merhaba Dunya ekledim
* 95e7356 Ilk commit
Buradan da aşikar olduğu üzere merge komutu ile yeni bir commit oluşturulmuş durumda. main branch'i artık bu commit'e bakıyor. Bu commit'in hash'i b5b6c09 iken, 1 değil 2 adet parent commit'e, yani 9a63d64 ve dc2243f commit'lerine baktığını görebiliyoruz. Soldaki graf ile bu birleşme terminal ortamındaki karakterler ile görselleştirilmiş. Bu görsellik bize daha karmaşık repository'lerde yardımcı olacak.
Peki bu merge commit'inin içinde ne var? Bunu yukarıda kullandığımız git show komutu ile gösterelim.
$ git show b5b6c09
commit b5b6c0910ab195204dec707b3370b8e70b47eabc (HEAD -> main)
Merge: 9a63d64 dc2243f
Author: <username> <email>
Date: Fri May 2 21:49:17 2025 +0200
Merge branch 'yeni-branch'
Burada herhangi bir dosya değişikliği gözükmüyor iken Merge: 9a63d64 dc2243f satırı gözümüze çarpıyor. Bu commit aslında içinde herhangi bir değişiklik barındırmıyor ve sadece 2 adet ayrı commit'e işaret ediyor. Yani aslında sadece bir yertutucu görevi görüyor. Bu özellikteki commit'lere merge commit adı verilmektedir.
Merge commit'i de değişiklik barındırabilir
İleride conflict terimine değindiğimizde merge commit'lerinin de değişiklik barındırabildiğini göreceğiz.
Buradan da anlaşılacağı üzere bir branch'i diğerine merge etmek aslında commit'leri kopyalamıyor, birleştirmiyor, değiştirmiyor. Bir branch'i diğerine merge etmek aslında commit graf'ına sadece bir düğüm daha ekliyor.
Terminoloji
merge komutu birden fazla branch'i aynı anda merge etmemize de olanak sağlıyor. Bunun sonucunda oluşan merge commit'inin 2'den fazla parent commit'i olabiliyor. Bu yöntem ile yapılan merge işlemlerine octopus merge deniliyor. Türkçeleştirmek istersek ahtapot birleşimi diyebiliriz ama bu çok sağlıklı bir karşılık olmaz.
Eğlenceli Bilgiler
-
GitHub'un maskotu olan ahtapot kedi Octocat, aslında Octopus ismindeki ufak bir kelime oyunundan gelmektedir. Bu fikir İngilizcede Octo ve Puss isimlerinin birleşiminden oluşan Octopuss isimli bir stok görselden ortaya çıkmıştır. Kaynak
-
Linux kernel geliştirmesi sırasında oluşan 66 parent'li bir merge commit'i hakkında bu yazıyı okumanızı tavsiye ederim.