Git İleri Seviye: Rebase, Cherry-pick ve Bisect Kullanımı
Git Rebase Nedir ve Nasıl Kullanılır?
Git rebase, bir branch'teki commit'leri başka bir branch'in üzerine taşımanızı sağlayan güçlü bir komuttur. Merge'den farklı olarak, rebase işlemi commit geçmişini lineer (düz bir çizgi) hâlinde tutar. Bu sayede proje geçmişi çok daha okunabilir olur.
Temel Rebase Kullanımı
Diyelim ki feature branch'inizde çalışıyorsunuz ve main branch'te yeni commit'ler var. Feature branch'inizi main'in en son hâlinin üzerine taşımak için:
git checkout feature
git rebase main
Bu komut, feature branch'indeki tüm commit'leri alır, geçici olarak bir kenara koyar, branch'i main'in son commit'ine taşır ve ardından commit'lerinizi teker teker üzerine uygular. Sonuç olarak, sanki main'in en güncel hâlinden branch almışsınız gibi temiz bir geçmiş elde edersiniz.
Interactive Rebase ile Commit Geçmişini Düzenleme
Interactive rebase, Git'in en güçlü özelliklerinden biridir. Son N commit'i düzenlemenize, birleştirmenize, sıralamanıza veya silmenize olanak tanır:
git rebase -i HEAD~5
Bu komut son 5 commit'i bir editörde açar. Her commit'in başında bir komut bulunur:
- pick — Commit'i olduğu gibi bırak
- reword — Commit mesajını değiştir
- edit — Commit'i durdur, değişiklik yapmana izin ver
- squash — Bir önceki commit ile birleştir (mesajları da birleşir)
- fixup — Squash gibi ama commit mesajını siler
- drop — Commit'i tamamen sil
Örneğin, PR açmadan önce "fix typo", "wip", "deneme" gibi dağınık commit'lerinizi tek bir anlamlı commit hâline getirmek için squash veya fixup kullanabilirsiniz:
pick a1b2c3d feat: kullanıcı profil sayfası eklendi
fixup d4e5f6g typo düzeltmesi
fixup h7i8j9k css düzeltmesi
pick k0l1m2n feat: profil fotoğrafı yükleme
Rebase Sırasında Çakışma (Conflict) Yönetimi
Rebase sırasında çakışma olursa Git durur ve sizden çözmenizi ister. Çakışmayı çözdükten sonra:
git add .
git rebase --continue
Rebase'den tamamen vazgeçmek isterseniz:
git rebase --abort
Önemli uyarı: Paylaşılan (remote'a push edilmiş) branch'lerde rebase yapmaktan kaçının. Rebase commit hash'lerini değiştirir, bu da diğer geliştiricilerin geçmişiyle çakışmaya neden olur.
Cherry-pick: Seçici Commit Taşıma
Cherry-pick, belirli bir commit'i alıp başka bir branch'e uygulamanızı sağlar. Rebase tüm commit'leri toplu olarak taşırken, cherry-pick tek tek seçim yapmanıza olanak tanır.
Temel Kullanım
# Belirli bir commit'i mevcut branch'e uygula
git cherry-pick abc1234
# Birden fazla commit'i sırayla uygula
git cherry-pick abc1234 def5678 ghi9012
# Bir aralıktaki commit'leri uygula (başlangıç commit'i dahil değil)
git cherry-pick abc1234..ghi9012
Cherry-pick Ne Zaman Kullanılır?
- Hotfix taşıma: Production branch'inde yapılan bir bug fix'i development branch'ine de uygulamak istediğinizde
- Yanlış branch'e yapılan commit: Bir commit'i yanlış branch'e yaptıysanız, doğru branch'e cherry-pick ile taşıyabilirsiniz
- Seçici özellik taşıma: Bir feature branch'inden sadece belirli commit'leri almak istediğinizde
Pratik Senaryo
Diyelim ki develop branch'inde kritik bir bug fix yaptınız ama bu düzeltmenin hemen production'a (main) gitmesi gerekiyor:
# Önce commit hash'ini bulun
git log --oneline develop
# Çıktı: f4a7b2e fix: ödeme sayfasında null pointer hatası düzeltildi
# main branch'ine geçin ve cherry-pick yapın
git checkout main
git cherry-pick f4a7b2e
Faydalı Cherry-pick Seçenekleri
# Commit yapmadan sadece değişiklikleri staged olarak getir
git cherry-pick --no-commit abc1234
# Merge commit'ini cherry-pick etmek için parent belirt
git cherry-pick -m 1 abc1234
# Çakışma durumunda iptal et
git cherry-pick --abort
Git Bisect: Bug'ın Kaynağını Otomatik Bulma
Git bisect, binary search (ikili arama) algoritmasını kullanarak bir hatanın hangi commit'te ortaya çıktığını bulmanızı sağlar. Yüzlerce commit arasından suçlu commit'i logaritmik zamanda tespit eder. Örneğin 1024 commit arasından sadece 10 adımda sorunu bulabilirsiniz.
Manuel Bisect Kullanımı
# Bisect oturumunu başlat
git bisect start
# Şu anki commit'in hatalı olduğunu belirt
git bisect bad
# Hatanın olmadığını bildiğiniz bir commit'i belirt
git bisect good v2.1.0
Bu noktada Git, iki commit arasındaki orta noktaya checkout yapar. Siz test edersiniz ve sonucu bildirirsiniz:
# Eğer bu commit'te hata varsa
git bisect bad
# Eğer bu commit'te hata yoksa
git bisect good
Git her seferinde aralığı yarıya böler ve sonunda hatayı tanıtan commit'i bulur. İşiniz bittiğinde:
git bisect reset
Otomatik Bisect: Test Script ile Kullanım
Bisect'in asıl gücü, bir test script'i ile tamamen otomatize edilebilmesidir. Script exit code 0 döndürürse "good", sıfır dışı döndürürse "bad" olarak değerlendirilir:
# Otomatik bisect başlat
git bisect start HEAD v2.1.0
git bisect run ./test-bug.sh
Örnek bir test-bug.sh script'i:
#!/bin/bash
# Projeyi derle
make build || exit 125 # 125 = bu commit atlanır (derlenmiyorsa)
# Testi çalıştır
python -c "from app import calculate_tax; assert calculate_tax(100) == 18"
Exit code 125 özel bir değerdir: Git'e bu commit'in test edilemeyeceğini söyler ve atlanır. Derleme hatası olan commit'ler için idealdir.
Bisect ile Pratik Bir Örnek
Diyelim ki kullanıcılarınız raporlama sayfasının çöktüğünü bildirdi. 2 hafta önce çalışıyordu ama tam olarak ne zaman bozulduğunu bilmiyorsunuz:
# 2 hafta önceki commit'i good olarak işaretle
git bisect start
git bisect bad HEAD
git bisect good HEAD~50
# Git size bir commit verir, test edin:
# Raporlama sayfasını açın → Çalışıyor mu?
git bisect good
# Git yeni bir commit verir, test edin:
# Raporlama sayfasını açın → Çöküyor mu?
git bisect bad
# Birkaç adım sonra Git suçlu commit'i bulur:
# "abc1234 is the first bad commit"
# Commit mesajı: "refactor: veritabanı sorgusu optimize edildi"
git bisect reset
Üç Komutun Birlikte Kullanımı
Bu üç komut birbirini tamamlar. Gerçek dünyada sıklıkla karşılaşılan bir iş akışı şöyle olabilir:
- Bisect ile production'daki bir bug'ın hangi commit'ten kaynaklandığını bulun
- Bug fix'i geliştirme branch'inizde yapın
- Cherry-pick ile bu düzeltmeyi doğrudan release branch'ine taşıyın
- Geliştirme branch'inizi rebase ile ana branch'e hizalayarak temiz bir geçmiş oluşturun
Özet ve İpuçları
- Rebase temiz ve lineer bir commit geçmişi sağlar ama paylaşılan branch'lerde dikkatli kullanılmalıdır
- Cherry-pick belirli değişiklikleri branch'ler arası taşımak için idealdir; hotfix senaryolarında vazgeçilmezdir
- Bisect büyük projelerde bug kaynağını bulmak için en verimli yöntemdir; mümkünse
bisect runile otomatize edin - Her üç komut da
--abortseçeneği sunar; bir şeyler ters giderse her zaman geri dönebilirsiniz - Rebase ve cherry-pick commit hash'lerini değiştirir;
force pushgerektirebilir, bu yüzden takım arkadaşlarınızı bilgilendirin