Git Worktree ile Birden Fazla Dalda Paralel Çalışma

Bir production ortamında acil bir hotfix yapman gerekiyor ama aynı zamanda yarın demoya girmesi gereken bir feature branch’inde çalışıyorsun. Klasik çözüm: her şeyi stash’le, branch değiştir, hotfix’i yap, tekrar geri dön, stash’i uygula ve umarım ki conflict çıkmaz. Bunu haftada birkaç kez yaşıyorsanız, Git worktree’yi neden daha önce öğrenmediğinize hayıflanacaksınız.

Git Worktree Nedir, Ne Değildir

Git’in worktree özelliği, aynı repository’nin farklı branch’lerini aynı anda farklı dizinlerde açık tutmanızı sağlar. Tek bir .git klasörü paylaşılır ama her worktree kendi bağımsız çalışma alanına sahiptir. Yani stash yok, branch switch yok, “bir saniye bekle benim değişikliklerim kaybolmasın” paniği yok.

Bunu “aynı repository’yi iki kere clone ettim” mantığıyla karıştırmayın. Klonlamada iki ayrı .git klasörünüz olur, object store iki kere disk kaplar, fetch/push senkronizasyonunu siz yönetmek zorunda kalırsınız. Worktree’de tek bir object store var, tüm alanlar onu paylaşıyor. Hem disk açısından verimli, hem de tutarlılık açısından çok daha sağlıklı.

Git 2.5 ile gelen bu özellik, 2.15 ve sonrasında oldukça olgunlaştı. Eğer sisteminizde eski bir Git versiyonu varsa, önce bunu kontrol edin:

git --version
# 2.15 altındaysanız güncelleyin, bazı worktree davranışları tutarsız

Temel Worktree Komutları

Sözdizimi oldukça basit. Mevcut branch’leri listelemekle başlayalım:

# Mevcut worktree'leri listele
git worktree list

# Çıktı şuna benzer:
# /home/user/myproject          abc1234 [main]
# /home/user/myproject-hotfix   def5678 [hotfix/login-bug]

Yeni bir worktree eklemek için git worktree add kullanıyoruz:

# Mevcut bir branch için worktree aç
git worktree add ../myproject-feature feature/new-dashboard

# Yeni branch oluşturarak worktree aç (-b flag'i ile)
git worktree add -b hotfix/critical-bug ../myproject-hotfix main

# Detached HEAD state ile belirli bir commit'e git
git worktree add --detach ../myproject-review abc1234def

Buradaki path convention’ına dikkat edin. Genellikle ana repository’nin yanına, benzer isimle bir dizin açmak en temiz yaklaşım. /home/user/myproject ana dizinse, /home/user/myproject-hotfix, /home/user/myproject-feature-x gibi bir yapı kullanmak dizin karmaşasını önler.

Gerçek Dünya: Hotfix Senaryosu

Sabah 09:00, production’da login sayfasında 500 hatası var. Siz de bu sırada önümüzdeki sprint’in büyük refactor’ını yapıyorsunuz, değişiklikleriniz yarım, commit’lenebilir durumda değil.

Eski yöntem ile yapacaklarınız:

# Eski acı yol
git stash push -m "refactor WIP"
git checkout main
git pull origin main
git checkout -b hotfix/login-500
# ... fix yap ...
git commit -am "fix: login 500 hatası düzeltildi"
git push origin hotfix/login-500
git checkout feature/big-refactor
git stash pop
# Umarım çakışma yoktur...

Worktree ile aynı senaryo:

# Ana dizinde hala refactor devam ederken
git worktree add -b hotfix/login-500 ../myproject-hotfix main

# Yeni terminalde
cd ../myproject-hotfix
# Burada tamamen bağımsız çalışma alanı var
# Dosyaları düzenle, test et

git add src/auth/login.py
git commit -m "fix: login 500 hatası - session timeout edge case"
git push origin hotfix/login-500

# Hotfix tamamlandı, worktree'yi temizle
cd ../myproject
git worktree remove ../myproject-hotfix

Ana dizindeki refactor çalışmanıza hiç dokunmadınız. Stash yok, branch switch yok.

Paralel Geliştirme: Feature Flag Senaryosu

Şirketinizde iki ekip aynı anda çalışıyor. Bir ekip API’yi yeniliyor, diğer ekip frontend’i yeniliyor. Sizin de her iki branch’i test etmeniz ve code review yapmanız gerekiyor. Üstelik kendi feature branch’inizde de bir şeyler var.

# Ana çalışma alanı - kendi feature'ınız
# /home/user/myproject  ->  feature/my-task

# API branch'ini review için aç
git worktree add ../myproject-api-review feature/new-api-endpoints

# Frontend branch'ini review için aç
git fetch origin feature/new-frontend
git worktree add ../myproject-fe-review feature/new-frontend

# Üç farklı terminalde üç farklı branch, aynı anda

Bu yapıda her worktree’de bağımsız olarak server başlatabilirsiniz. Birinde API’yi 8001’de, diğerinde frontend’i 3001’de çalıştırın, entegrasyon testlerini paralel yapın. Bu işi eskiden docker ile ya da VM snapshot’ları ile yapmaya çalışırdık.

IDE Entegrasyonu ve Dikkat Edilmesi Gerekenler

VS Code kullanıyorsanız, her worktree dizinini ayrı bir pencerede açabilirsiniz. File > Open Folder ile her worktree dizini bağımsız bir proje gibi davranır. JetBrains IDE’lerinde de durum aynı; her dizin için ayrı proje açılabilir.

Ama şu noktalar sizi yanıltmasın:

Aynı branch iki worktree’de açılamaz. Bu Git’in temel kısıtlaması. Eğer feature/abc branch’i bir worktree’de açıksa, başka bir worktree’de aynı branch’i açmaya çalıştığınızda hata alırsınız:

git worktree add ../myproject-copy feature/abc
# fatal: 'feature/abc' is already checked out at '/home/user/myproject'

Bunun mantıklı bir nedeni var: aynı branch’in iki farklı yerde eş zamanlı değiştirilmesi tutarsızlıklara yol açar.

.git dizini hakkında yanlış anlamalar: Linked worktree dizinlerine gittiğinizde .git dosyası (dizin değil, dosya) görürsünüz. Bu dosya asıl .git dizinini işaret eden bir pointer’dır:

cat ../myproject-hotfix/.git
# gitdir: /home/user/myproject/.git/worktrees/myproject-hotfix

Bu normal ve beklenen bir durum.

Worktree ile Birlikte Çalışma: Gelişmiş Senaryolar

Bare Repository ile Worktree

Bu yaklaşımı özellikle CI/CD pipeline’larında veya sunucu tarafı iş akışlarında görebilirsiniz. Ana repository’yi --bare olarak klonlayıp, tüm çalışma alanlarını worktree olarak yönetmek mümkün:

# Bare repository oluştur
git clone --bare [email protected]:company/myproject.git myproject.git

cd myproject.git

# Her branch için worktree aç
git worktree add ../myproject-main main
git worktree add ../myproject-staging staging
git worktree add ../myproject-develop develop

Bu yapı özellikle deployment scriptlerinde çok temiz bir ayrım sağlar. Her ortamın kodu farklı dizinde, tek komutla güncelleme yapılabilir:

# Staging'i güncelle
cd ../myproject-staging
git pull origin staging

# Production'ı güncelle
cd ../myproject-main
git pull origin main

Worktree Üzerinde Rebase ve Merge

Bir worktree’deyken diğer branch’leri etkileyecek işlemler yapabilirsiniz. Ama dikkatli olun; bir worktree’de bir branch checkout’tayken, başka bir worktree’den o branch üzerinde destructive işlem yapmak tehlikeli:

# YANLIŞ: hotfix branch'i başka bir worktree'de açıkken
# ana worktree'den şu komutu çalıştırmak sorun çıkarır:
git branch -D hotfix/login-500  # Bu branch hala linked worktree'de!

# DOĞRU: Önce worktree'yi kaldır, sonra branch'i sil
git worktree remove ../myproject-hotfix
git branch -D hotfix/login-500

Rebase işlemlerinde de benzer dikkat gerekli:

# Hotfix worktree'sindeyken main'i rebase almak güvenli
cd ../myproject-hotfix
git rebase origin/main

# Bu işlem ana worktree'deki çalışmayı etkilemez

Worktree’leri Temizleme ve Yönetme

Zamanla biriken worktree’ler disk alanı ve referans karmaşası yaratır. Düzenli temizlik önemli:

# Belirli bir worktree'yi kaldır
git worktree remove ../myproject-hotfix

# Eğer worktree dizinini elle sildiyseniz, dangling referansları temizle
git worktree prune

# Prune işlemini ne yapacağını görmek için dry-run
git worktree prune --dry-run

# Verbose çıktı ile prune
git worktree prune -v

git worktree prune komutu özellikle önemli. Eğer bir worktree dizinini rm -rf ile elle sildiyseniz, Git hala o referansı .git/worktrees/ altında tutar. prune komutu bu zombi referansları temizler.

Worktree’lerin durumunu düzenli kontrol etmek için:

git worktree list --porcelain

# Çıktı daha detaylı olur:
# worktree /home/user/myproject
# HEAD abc1234def
# branch refs/heads/main
#
# worktree /home/user/myproject-hotfix
# HEAD def5678abc
# branch refs/heads/hotfix/login-500

Lock Mekanizması

Bazı durumlarda worktree’lerin silinmesini engellemek isteyebilirsiniz. Örneğin bir CI job’ı uzun süre çalışıyorsa ve bu işlem sırasında worktree’nin silinmemesini garantilemek istiyorsunuz:

# Worktree'yi kilitle (isteğe bağlı mesajla)
git worktree lock ../myproject-ci-job --reason "CI pipeline devam ediyor"

# Kilidini aç
git worktree unlock ../myproject-ci-job

# Kilitli worktree'yi zorla silmek için
git worktree remove --force ../myproject-ci-job

Lock mekanizması özellikle paylaşılan geliştirme sunucularında, birden fazla kişinin aynı repository’yi kullandığı senaryolarda hayat kurtarır.

Shell Alias ve Script Entegrasyonu

Worktree iş akışını daha da hızlandırmak için bazı alias’lar ve helper scriptler tanımlamak mantıklı. Bunları .bashrc veya .zshrc‘ye ekleyebilirsiniz:

# ~/.bashrc veya ~/.zshrc
alias gwl='git worktree list'
alias gwp='git worktree prune'

# Hızlı hotfix worktree oluşturucu
gwhotfix() {
    local branch_name="hotfix/${1}"
    local dir_name="../$(basename $(pwd))-hotfix"
    git worktree add -b "${branch_name}" "${dir_name}" main
    cd "${dir_name}"
    echo "Hotfix worktree hazır: ${dir_name} -> ${branch_name}"
}

# Review worktree oluşturucu
gwreview() {
    local branch_name="${1}"
    local safe_name=$(echo "${branch_name}" | tr '/' '-')
    local dir_name="../$(basename $(pwd))-review-${safe_name}"
    git fetch origin "${branch_name}"
    git worktree add "${dir_name}" "${branch_name}"
    cd "${dir_name}"
    echo "Review worktree hazır: ${dir_name}"
}

Bu script’lerle kullanım şu kadar basit hale gelir:

# Hotfix için
gwhotfix critical-payment-bug
# Otomatik olarak hotfix/critical-payment-bug branch'i oluşturur
# ../myproject-hotfix dizinine geçer

# Code review için
gwreview feature/new-dashboard
# Origin'den fetch eder, worktree açar, dizine geçer

Yaygın Hatalar ve Çözümleri

Pratikte en sık karşılaşılan sorunları ve çözümlerini paylaşayım:

Problem: git worktree add sonrası submodule’ler eksik

# Worktree'ye geçtikten sonra
cd ../myproject-feature
git submodule update --init --recursive
# Her worktree için submodule'leri ayrıca init etmek gerekiyor

Problem: node_modules, vendor gibi dizinler her worktree’de tekrar kurmak gerekiyor

Bu aslında bir hata değil, worktree’nin doğru davranışı. Her worktree bağımsız bir çalışma alanı olduğundan, dependency’leri ayrı kurmanız gerekir. Bunu script ile otomatize etmek en temiz çözüm:

gwreview() {
    local branch_name="${1}"
    local dir_name="../$(basename $(pwd))-review-$(echo ${branch_name} | tr '/' '-')"
    git fetch origin "${branch_name}"
    git worktree add "${dir_name}" "${branch_name}"
    cd "${dir_name}"
    # Projeye göre uyarla
    if [ -f "package.json" ]; then
        npm install
    elif [ -f "requirements.txt" ]; then
        pip install -r requirements.txt
    fi
}

Problem: .env dosyaları worktree’ye taşınmıyor

.gitignore‘da olan dosyalar worktree’ye kopyalanmaz, bu beklenen davranış. .env.example‘dan kopyalayabilir veya sembolik link kullanabilirsiniz:

cd ../myproject-feature
ln -s /home/user/myproject/.env .env

Worktree Kullanımı Gereken ve Gereksiz Durumlar

Her şey için worktree kullanmak şart değil. Birkaç dakikalık bir branch değişikliği için, değişiklikleriniz clean state’deyse normal git checkout hala en hızlı yol.

Worktree’nin gerçekten değer kattığı durumlar:

  • Uzun süren bir feature üzerinde çalışırken acil müdahale gerektiğinde
  • Code review yaparken kendi çalışmanızı durdurmak istemediğinizde
  • Aynı anda birden fazla branch’i test etmeniz veya karşılaştırmanız gerektiğinde
  • CI/CD altyapısında farklı branch’lerin aynı anda build edilmesi gerektiğinde
  • Pair programming veya mob programming sırasında farklı dalları paralel göstermek için

Worktree’nin çok da anlam ifade etmediği durumlar ise şunlar:

  • Sadece dosya farkını görmek istiyorsanız git diff branch1..branch2 yeterli
  • Çok kısa süreli branch değişiklikleri için, yönetim overhead’i değmez
  • Disk alanının kritik olduğu ortamlarda, her worktree ayrı bir çalışma kopyası demek

Sonuç

Git worktree, öğrenme maliyeti son derece düşük ama günlük verimliliğe etkisi oldukça yüksek bir özellik. Bir hafta boyunca acil durumlar için hotfix senaryosunda, code review için branch incelemelerinde kullanın; stash/unstash döngüsüne ve branch switch telaşına ne kadar az girdiğinizi göreceksiniz.

Özellikle bare repository ile worktree kombinasyonu, deployment scriptleri ve CI sistemleri için harika bir pattern. Sunucu tarafında “bu path her zaman main’in son halini içerir, şu path staging’i içerir” garantisi vermek, Nginx veya uygulama sunucusu konfigürasyonlarını statik tutmanızı sağlar.

Worktree komutlarını bir şablon haline getirip, ekibinizdeki herkesin gwhotfix veya gwreview gibi alias’ları kullanmasını sağlarsanız, onboarding süreçlerinde de ciddi bir kolaylık yaratırsınız. “Acil hotfix yapmak için ne yapıyoruz?” sorusunun cevabı tek bir komut haline gelir.

Başlamak için gerçekten tek bir şeye ihtiyacınız var: bir dahaki acil durumda stash’e uzanmak yerine git worktree add yazın.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir