Branch Nedir?
Giriş: Neden Dallanma Öğreniyoruz?
Şu ana kadar tek bir çizgide ilerledik — bir commit'in ardına bir commit daha. Ama gerçek dünyada yazılım böyle geliştirilmez. Düşün:
Sen login sayfasını geliştirirken, ekip arkadaşın ödeme sistemini yapıyor
Bir bug fix acil gönderilmeli ama henüz yarım kalmış bir özellik üzerinde çalışıyorsun
Yeni bir fikri denemek istiyorsun ama ana projeyi bozmak istemiyorsun
Bu durumların hepsinin cevabı aynı: branch (dal).
Branch, Git'in en güçlü ve en çok sevilen özelliği. SVN zamanında branching bir kabustu — dosyalar kopyalanır, sunucu yavaşlar, birleştirme acı verirdi. Git'te ise bir branch oluşturmak milisaniyeler sürer. Bu hız farkı, Git'in branching'i bir günlük araç haline getirmesini sağladı.
🎬 Analoji: Paralel Evrenler
Branch'leri paralel evrenler gibi düşün.
Ana evrenin var — main branch. Her şey burada stabil, çalışır durumda. Sonra bir portal açıyorsun: "Şu özelliği geliştirelim" diyorsun ve yeni bir evrene adım atıyorsun. Bu evrende istediğini yap — dene, boz, düzelt. Ana evren bundan etkilenmez.
Özellik hazır olduğunda? İki evreni birleştirirsin (merge). Deney başarısız olursa? Paralel evreni kapat, ana evren hiç etkilenmemiş.
Ana Evren (main): ───●───●───●───●───●───●───►
│ ▲
│ Portal aç │ Birleştir (merge)
▼ │
Paralel Evren (feature): ········●───●───●───●──┘
Dene, geliştirBranch Nasıl Çalışır? (İç Yapı)
Branch = Sadece Bir İşaretçi (Pointer)
Git'te branch, görkemli bir yapı değildir. Sadece bir dosya ve o dosyanın içinde bir commit hash'i var. Hepsi bu.
$ cat .git/refs/heads/main
d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w341 byte'lık bir dosya. Bu yüzden branch oluşturmak bedava — yeni bir dosya oluşturup içine bir hash yazmak kadar hızlı.
Branch'lerin gerçek yapısı:
.git/refs/heads/
├── main → d4e5f6g... (commit hash)
├── feature → a1b2c3d... (commit hash)
└── bugfix → h7i8j9k... (commit hash)
Her branch, bir commit'e işaret eden bir pointer.
Yeni commit yapılınca, aktif branch ilerler.HEAD: "Hangi Branch'tesin?"
HEAD, şu anda hangi branch'te olduğunu gösterir:
$ cat .git/HEAD
ref: refs/heads/mainHEAD → main → commit d4e5f6g
Branch değiştirdiğinde HEAD dosyası güncellenir:
$ git checkout feature
$ cat .git/HEAD
ref: refs/heads/featureGörsel: Branch ve Commit Zinciri
Başlangıç — tek branch:
[A] ← [B] ← [C]
▲
main
▲
HEAD
"feature" branch'i oluştur:
[A] ← [B] ← [C]
▲
main
feature ← yeni branch, aynı commit'i gösteriyor
▲
HEAD (hâlâ main'de)
feature'a geç ve commit yap:
[A] ← [B] ← [C]
▲ \
main [D] ← [E]
▲
feature
▲
HEAD (şimdi feature'da)
main'e geri dön ve commit yap:
[F]
/ ▲
[A] ← [B] ← [C] main ← HEAD
\
[D] ← [E]
▲
featureİki branch bağımsız olarak ilerliyor. Birbirlerinden habersiz. Birini değiştirmek diğerini etkilemiyor.
Branch Oluşturma
git branch ile Oluşturma
# Yeni branch oluştur (ama geçiş yapma)
$ git branch feature-login
# Branch'leri listele
$ git branch
feature-login
* main ← yıldız = aktif branch (HEAD'in gösterdiği)
# Branch'in gösterdiği commit
$ git log --oneline -1 feature-login
d4e5f6g feat: İletişim formu eklendi
# main ile aynı commit'te — çünkü henüz yeni oluşturuldugit checkout -b ile Oluştur ve Geç
# Oluştur + geç (en yaygın kullanım)
$ git checkout -b feature-login
Switched to a new branch 'feature-login'
$ git branch
* feature-login ← artık buradayız
maingit switch -c ile Oluştur ve Geç (Modern)
Git 2.23'te switch komutu eklendi. checkout'tan daha net:
# Oluştur + geç (modern yol)
$ git switch -c feature-login
Switched to a new branch 'feature-login'💡 İpucu:
git checkouthem branch değiştirmek hem dosya geri yüklemek için kullanılıyordu (kafa karıştırıcı). Git 2.23'te bu iki iş ayrıldı: -git switch→ branch değiştir -git restore→ dosya geri yükle İkisi de çalışır ama yenilerini tercih et — niyetin daha açık.
Belirli Commit'ten Branch Oluşturma
# Eski bir commit'ten branch başlat
$ git branch hotfix a1b2c3d
# Uzak branch'ten yerel branch oluştur
$ git checkout -b feature origin/feature
# veya
$ git switch -c feature origin/featureBranch'ler Arası Geçiş
git checkout veya git switch
# main'e geç
$ git checkout main
Switched to branch 'main'
# veya modern yol
$ git switch main
Switched to branch 'main'
# feature-login'e geç
$ git switch feature-login
Switched to branch 'feature-login'Branch değiştirdiğinde ne olur?
Git, working directory'deki dosyaları hedef branch'in son commit'indeki hale getirir:
# feature-login branch'inde login.html var
$ ls
index.html login.html style.css
# main'e geç
$ git switch main
$ ls
index.html style.css
# login.html kayboldu! (main'de yok çünkü)
# feature-login'e geri dön
$ git switch feature-login
$ ls
index.html login.html style.css
# login.html geri geldi!Git, dosyaları sanki sihirli bir şekilde değiştiriyor. Ama aslında .git/objects'ten doğru versiyonları çıkarıyor.
⚠️ Dikkat: Branch değiştirmeden önce commit'lenmemiş değişikliklerini ya commit'le ya da
stash'le. Aksi halde Git seni uyarır veya değişiklikleri diğer branch'e taşır (kafa karıştırıcı durumlar yaratabilir).
# Commit'lenmemiş değişiklik varken branch değiştirmeye çalışmak
$ git switch main
error: Your local changes to the following files would be overwritten by checkout:
login.html
Please commit your changes or stash them before you switch branches.
# Çözüm 1: Commit'le
$ git add . && git commit -m "WIP: Login devam ediyor"
$ git switch main
# Çözüm 2: Stash'le (geçici olarak sakla)
$ git stash
$ git switch main
# İşin bitince geri gel ve stash'i geri al
$ git switch feature-login
$ git stash popBranch Listeleme
# Yerel branch'ler
$ git branch
feature-login
hotfix-nav
* main
# Uzak (remote) branch'ler
$ git branch -r
origin/main
origin/feature-login
origin/develop
# Tümü (yerel + uzak)
$ git branch -a
feature-login
hotfix-nav
* main
remotes/origin/main
remotes/origin/feature-login
remotes/origin/develop
# Son commit bilgisiyle birlikte
$ git branch -v
feature-login a1b2c3d feat: Login formu eklendi
hotfix-nav d4e5f6g fix: Nav hizalama düzeltildi
* main h7i8j9k feat: Proje başlatıldı
# Hangi branch'ler main'e merge edilmiş?
$ git branch --merged main
feature-login ← merge edilmiş, silinebilir
* main
# Hangi branch'ler henüz merge edilmemiş?
$ git branch --no-merged main
hotfix-nav ← henüz merge edilmemişBranch Silme
Merge Edilmiş Branch'i Silme
# Güvenli silme (merge edilmişse siler, edilmemişse uyarır)
$ git branch -d feature-login
Deleted branch feature-login (was a1b2c3d).Merge Edilmemiş Branch'i Silme (Zorla)
# Merge edilmemiş branch'i zorla sil
$ git branch -d deneme
error: The branch 'deneme' is not fully merged.
If you are sure you want to delete it, run 'git branch -D deneme'.
# Tamam, siliyorum
$ git branch -D deneme
Deleted branch deneme (was f7g8h9i).-d = safe delete (merge edilmişse sil) -D = force delete (ne olursa olsun sil)
⚠️ Dikkat: Branch silmek sadece işaretçiyi siler. Commit'ler hâlâ
objectsdizininde var (bir süreliğine). Yanlışlıkla sildiysengit reflogile commit hash'ini bulup yeni branch oluşturabilirsin:git branch kurtarma abc1234.
Uzak Branch Silme
# Uzak branch'i sil
$ git push origin --delete feature-login
To github.com:tolgahan/proje.git
- [deleted] feature-loginBranch İsimlendirme Kuralları
İyi isimlendirme, ekip çalışmasında hayat kurtarır:
# ✅ İyi isimlendirme
feature/user-authentication
feature/shopping-cart
bugfix/login-redirect
hotfix/security-patch
docs/api-documentation
refactor/database-layer
release/v2.1.0
# ❌ Kötü isimlendirme
yeni-branch
test
aaa
tolgahan
fix
my-branchYaygın konvansiyonlar:
feature/ → Yeni özellik
bugfix/ → Bug düzeltme (planlı)
hotfix/ → Acil düzeltme (production)
release/ → Sürüm hazırlığı
docs/ → Dokümantasyon
refactor/ → Kod yapılandırma
test/ → Test ekleme
chore/ → Bakım işleriPratik Senaryo: Branch Workflow
# === PROJE BAŞLAT ===
$ mkdir branch-lab && cd branch-lab && git init
$ echo "<h1>Branch Lab</h1>" > index.html
$ git add . && git commit -m "feat: Proje başlatıldı"
# === YENİ ÖZELLİK GELİŞTİR ===
$ git switch -c feature/about-page
$ echo "<h2>Hakkımda</h2>" > about.html
$ git add . && git commit -m "feat: Hakkımda sayfası eklendi"
$ echo "<p>Ben bir geliştiriciyim</p>" >> about.html
$ git add . && git commit -m "feat: Hakkımda içeriği eklendi"
# === ANA PROJEYE DÖN ===
$ git switch main
$ ls
index.html # about.html yok! (main'de henüz yok)
# === ACİL BUG FIX ===
$ git switch -c hotfix/typo-fix
$ echo "<h1>Branch Lab - Düzeltildi</h1>" > index.html
$ git add . && git commit -m "fix: Başlıktaki yazım hatası düzeltildi"
# === LOG'A BAK ===
$ git log --oneline --graph --all
* abc1234 (hotfix/typo-fix) fix: Başlıktaki yazım hatası düzeltildi
| * def5678 (feature/about-page) feat: Hakkımda içeriği eklendi
| * ghi9012 feat: Hakkımda sayfası eklendi
|/
* jkl3456 (HEAD -> main) feat: Proje başlatıldı
# Güzel! 3 branch, birbirinden bağımsız.
# Merge işlemini bir sonraki derste öğreneceğiz.
# === TEMİZLİK ===
# Merge sonrası (bir sonraki ders):
$ git branch -d hotfix/typo-fix
$ git branch -d feature/about-pageBranch Yeniden Adlandırma
Branch isimlendirmesinde hata yaptıysan veya konvansiyonu değiştirmek istiyorsan:
# Yerel branch'i yeniden adlandır (üzerindeyken)
$ git branch -m yeni-isim
# Yerel branch'i yeniden adlandır (başka branch'teyken)
$ git branch -m eski-isim yeni-isim
# Remote'taki branch'i yeniden adlandır (eski sil, yeni push'la)
$ git push origin :eski-isim
$ git push -u origin yeni-isimPratik örnek:
# master'ı main'e çevirmek (birçok proje bunu yaptı)
$ git branch -m master main
$ git push -u origin main
$ git push origin --delete master
# GitHub'da varsayılan branch'i değiştir:
# Settings → Branches → Default branch → main💡 İpucu: GitHub, Settings → Branches menüsünden varsayılan branch'i tek tıkla değiştirmenize izin verir. Mevcut PR'lar ve branch protection kuralları otomatik güncellenir.
Detached HEAD — "Kafası Kopuk" Durum
Normal durumda HEAD bir branch'e işaret eder. Ama bazen HEAD doğrudan bir commit'e işaret edebilir — buna Detached HEAD denir.
# Belirli bir commit'e checkout yaparsak:
$ git checkout a1b2c3d
Note: switching to 'a1b2c3d'.
You are in 'detached HEAD' state. You can look around, make
experimental changes and commit them, and you can discard any
commits you make in this state...
# HEAD artık bir branch'e değil, doğrudan commit'e işaret ediyor
$ cat .git/HEAD
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
# Normal: "ref: refs/heads/main"
# Detached: doğrudan hashNormal HEAD: Detached HEAD:
[A] ← [B] ← [C] [A] ← [B] ← [C]
▲ ▲
main main
▲
HEAD [B] ← HEAD (doğrudan commit)Ne zaman olur?
Eski bir commit'e
git checkout hashile gidersinBir tag'e checkout yaparsın:
git checkout v1.0Rebase sırasında
Tehlike: Detached HEAD'de commit yaparsan ve sonra başka branch'e geçersen, o commit'ler hiçbir branch'a ait olmaz ve kaybolabilir:
# Detached HEAD'de commit yaptın
$ git commit -m "önemli değişiklik"
[detached HEAD f9a8b7c] önemli değişiklik
# Sonra branch'e geri döndün
$ git checkout main
Warning: you are leaving 1 commit behind, not connected to
any of your branches...
# 😱 Commit yetim kaldı!
# Kurtarma: O commit'ten yeni branch oluştur
$ git branch kurtarma f9a8b7c
$ git checkout kurtarma
# Commit güvende! ✅⚠️ Dikkat: Detached HEAD'deyken deneysel değişiklikler yapmak sorun değil — ama keşfettiğin bir şeyi korumak istiyorsan mutlaka
git checkout -b yeni-branchile branch oluştur. Aksi haldegit gcbir süre sonra o commit'leri temizler.
Branch Karşılaştırma
İki branch arasındaki farkları görmek günlük çalışmada çok kullanışlıdır:
# İki branch arasındaki commit farkı
$ git log main..feature/login --oneline
d4e5f6g feat: Login form validasyonu
a1b2c3d feat: Login sayfası eklendi
# feature'da olup main'de olmayan commit'ler
# Tam tersi — main'de olup feature'da olmayan
$ git log feature/login..main --oneline
h7i8j9k fix: Header düzeltmesi
# Bu commit'ler feature'a merge edilmemiş
# İki branch arasındaki dosya farkları
$ git diff main..feature/login
# Tüm farklılıkları gösterir
# Sadece değişen dosya isimleri
$ git diff main..feature/login --name-only
src/login.js
src/auth.service.js
styles/login.css
# Branch'lerin ortak atasını bul
$ git merge-base main feature/login
a1b2c3d4... # İki branch'in ayrıldığı noktaBu komutlar özellikle PR açmadan önce "ne değiştirdim?" sorusuna cevap vermek için çok kullanışlıdır.
Yaygın Hatalar
1. main'e Doğrudan Commit Atmak
# ❌ main branch'inde commit yapmak
$ git checkout main
$ echo "yeni özellik" > feature.js
$ git add . && git commit -m "feat: Yeni özellik"
# Direkt main'e commit attın! Ekip çalışmasında kabus.
# ✅ Önce branch aç
$ git checkout -b feature/new-thing
$ echo "yeni özellik" > feature.js
$ git add . && git commit -m "feat: Yeni özellik"
# PR açarak merge et2. Commit'lenmemiş Değişikliklerle Branch Değiştirmek
# ❌ Yarım kalmış değişiklikler branch'ler arasında taşınır
$ git checkout main
$ echo "yarım iş" > dosya.txt # commit'lemeden
$ git checkout feature
# dosya.txt feature branch'ine de taşınabilir!
# ✅ Önce commit'le veya stash'le
$ git stash
$ git checkout feature
$ git stash pop # İşin bitince geri al3. Yanlış Branch'te Çalışmak
# ❌ main'de olduğunu sanıyordun ama feature'dasın
$ git branch # Hangi branch'tesin kontrol et!
# ✅ Prompt'una branch adını ekle (çok faydalı)
# .bashrc veya .zshrc'ye ekle:
parse_git_branch() {
git branch 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \W\$(parse_git_branch) $ "
# Artık terminal: user@host project (feature/login) $4. Branch'leri Temizlememek
# ❌ Merge edilen branch'ler birikmiş
$ git branch
bugfix/old-issue
feature/completed-1
feature/completed-2
feature/completed-3
* main
test-123
wip-something
# ✅ Merge edilmiş branch'leri temizle
$ git branch --merged main | grep -v "main" | xargs git branch -d
# Tek komutla tüm merge edilmiş branch'ler silinir
# Remote'taki stale referansları temizle
$ git fetch --prune5. Branch İsminde Boşluk veya Özel Karakter Kullanmak
# ❌ Boşluk ve özel karakterler
$ git branch "yeni özellik" # HATA!
$ git branch feature@login # Sorunlu!
# ✅ Tire ve slash kullan
$ git branch feature/login-page # ✅
$ git branch bugfix/fix-42 # ✅Branch Best Practices
1. main Branch Kutsal
main (veya master) branch'i her zaman çalışır, deploy edilebilir durumda tutun. Doğrudan main'e commit atma — branch aç, çalış, merge et.
2. Kısa Ömürlü Branch'ler
Branch'ler günler içinde yaşamalı, haftalar değil. Uzun yaşayan branch'ler merge conflict kabusu yaratır. İdeal branch ömrü: 1-3 gün.
3. Branch = Görev
Her branch bir görevi temsil etmeli. "Login sayfası" bir branch, "ödeme sistemi" başka bir branch. Bir branch'te birden fazla görev yapma.
4. Silmeyi Unutma
Merge edilen branch'leri sil. Yoksa branch listesi çöplüğe döner.
5. Düzenli Senkronizasyon
Feature branch'inde çalışırken main'deki değişiklikleri düzenli olarak branch'ine al:
$ git checkout feature/my-work
$ git merge main
# veya
$ git rebase mainBu, büyük conflict'leri önler.
6. Branch İsminde Ticket/Issue Numarası
# Ticket tracking ile bağlantı kur
$ git checkout -b feature/JIRA-123-user-auth
$ git checkout -b fix/GH-42-login-redirect
# Log'da aranabilir, PR'da otomatik linklenebilirÖzet
Branch, bir commit'e işaret eden hafif bir pointer'dır — oluşturmak sadece 41 byte'lık bir dosya yazmaktır
HEAD, şu anda hangi branch'te olduğunu gösterir — branch değiştirmek HEAD'i günceller
git branch isimile oluştur,git switch -c isimile oluştur + geçBranch değiştirdiğinde working directory o branch'in son commit'ine güncellenir
`-d` ile güvenli silme, `-D` ile zorla silme yapılır
İsimlendirmede `feature/`, `bugfix/`, `hotfix/` gibi prefix'ler kullan — okunabilirlik önemli
*Bir sonraki derste branch'leri birleştirmeyi (merge) öğreneceğiz — fast-forward, 3-way merge ve merge commit!*
AI Asistan
Sorularını yanıtlamaya hazır