← Kursa Dön
📄 Text · 30 min

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ştir

Branch 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
d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3

41 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/main

HEAD → main → commit d4e5f6g

Branch değiştirdiğinde HEAD dosyası güncellenir:

$ git checkout feature
$ cat .git/HEAD
ref: refs/heads/feature

Gö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şturuldu

git 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
  main

git 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 checkout hem 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/feature

Branch'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 pop

Branch 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â objects dizininde var (bir süreliğine). Yanlışlıkla sildiysen git reflog ile 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-login

Branch İ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-branch

Yaygı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şleri

Pratik 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-page

Branch 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-isim

Pratik ö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 hash
Normal 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 hash ile gidersin

  • Bir tag'e checkout yaparsın: git checkout v1.0

  • Rebase 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-branch ile branch oluştur. Aksi halde git gc bir 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ığı nokta

Bu 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 et

2. 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 al

3. 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 --prune

5. 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 main

Bu, 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 isim ile oluştur, git switch -c isim ile 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!*