Git ile Büyük Dosya Yönetimi: Git LFS Kullanımı
Bir gün ekip arkadaşım Slack’ten mesaj attı: “Repository’yi clone edemiyorum, bağlantım çok yavaş, ne yapayım?” Durumu incelediğimde reponun 4GB’a şiştiğini gördüm. İçinde tasarım ekibinin eklediği PSD dosyaları, test videoları ve onlarca binary vardı. İşte o gün Git LFS’i ciddiye almaya başladım.
Git, metin tabanlı dosyaları yönetmek için mükemmel bir araç. Ama büyük binary dosyalar söz konusu olduğunda işler çirkinleşmeye başlıyor. Her commit’te o dosyanın tamamı repository’e gömülüyor, clone süreleri uzuyor, disk kullanımı patlıyor. Git Large File Storage (LFS), tam da bu sorunu çözmek için var.
Git LFS Nedir, Ne Değildir?
Git LFS, büyük dosyaların içeriğini doğrudan repository’de saklamak yerine ayrı bir depolama alanında tutan ve Git’e sadece bir pointer (işaretçi) dosyası bırakan bir uzantı. Yani Git tarihinde o büyük dosya yerine küçük bir metin dosyası görürsünüz, asıl içerik ise LFS sunucusunda tutulur.
Neyin büyük dosya sayıldığına kendiniz karar veriyorsunuz. Genel kabul görmüş eşikler şöyle:
- 50MB altı: Git ile direkt yönetilebilir, sorun yok
- 50MB – 100MB arası: Dikkatli olun, sık değişiyorsa LFS düşünün
- 100MB üzeri: Kesinlikle LFS veya başka bir çözüm
LFS’in sizi kurtarmayacağı durumlar da var. Eğer o büyük dosya çok sık değişiyorsa ve her versiyonunu saklamak istiyorsanız, depolama maliyetleri yine de artacak. LFS sizi transfer acısından kurtarır, depolama maliyetinden değil.
Kurulum
Git LFS ayrı bir araç, Git ile birlikte gelmiyor. Sisteminize göre kurulum:
# Ubuntu/Debian
sudo apt-get install git-lfs
# RHEL/CentOS/Rocky Linux
sudo dnf install git-lfs
# macOS
brew install git-lfs
# Windows (Chocolatey)
choco install git-lfs
Kurulumdan sonra bir kez global olarak aktif etmeniz gerekiyor:
git lfs install
Bu komut ~/.gitconfig dosyanıza gerekli filter konfigürasyonunu ekler. Sisteminizde Git kullanan her kullanıcının bunu bir kez çalıştırması gerekiyor. CI/CD pipeline’larınızı da unutmayın, build agent’larınızda da bu adım olmalı.
Bir Repository’de LFS’i Aktif Etmek
Yeni bir proje başlatıyorsanız işler kolay:
mkdir proje && cd proje
git init
git lfs install
# Hangi dosya türlerini LFS ile takip etmek istiyorsunuz?
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "*.zip"
git lfs track "*.iso"
# .gitattributes dosyasını da commit etmeyi unutmayın
git add .gitattributes
git commit -m "Git LFS konfigürasyonu eklendi"
git lfs track komutu .gitattributes dosyasına satır ekler. Bu dosyayı elle de düzenleyebilirsiniz:
cat .gitattributes
Çıktı şuna benzer bir şey olacak:
*.psd filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.iso filter=lfs diff=lfs merge=lfs -text
Belirli bir dizindeki her şeyi LFS’e almak için:
git lfs track "assets/**"
git lfs track "build/output/*.jar"
Mevcut Repository’yi LFS’e Geçirmek
İşte gerçek zorluk burada. Elimizde şişmiş bir repo var ve tarihini temizlemek istiyoruz. Bu iş biraz cerrahi müdahale gerektiriyor.
Önce durumu analiz edelim:
# Repository'deki en büyük dosyaları bul
git rev-list --objects --all |
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
awk '/^blob/ {print substr($0,6)}' |
sort --numeric-sort --key=2 |
tail -20 |
cut --complement --characters=13-40 |
numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Bu komut size tarihteki en büyük 20 dosyayı boyutlarıyla listeler. Hangi dosyaların sorun çıkardığını görürsünüz.
Şimdi git lfs migrate komutu devreye giriyor. Bu araç, mevcut Git tarihini yeniden yazarak büyük dosyaları LFS’e taşımanızı sağlıyor:
# Önce durumu analiz et
git lfs migrate info --everything --above=10mb
# Tüm tarihi göç ettir (main branch dahil)
git lfs migrate import --everything --above=10mb
# Sadece belirli dosya türlerini göç ettir
git lfs migrate import --everything --include="*.psd,*.mp4,*.zip"
Dikkat: --everything parametresi tüm branch ve tag geçmişini yeniden yazıyor. Bu işlem sonrası tüm takım arkadaşlarınızın repo’yu yeniden clone etmesi gerekecek. Bunu hafife almayın, önceden haber verin.
Göç tamamlandıktan sonra force push gerekiyor:
git push origin --force --all
git push origin --force --tags
Günlük Kullanım
LFS kurulduktan sonra günlük iş akışınız neredeyse değişmiyor. git add, git commit, git push aynen çalışıyor. Tek fark, büyük dosyalar artında perde gerisinde LFS’e gönderiliyor.
# Büyük bir dosya ekleyin
cp /tmp/tasarim-dosyasi.psd ./assets/
git add assets/tasarim-dosyasi.psd
git commit -m "Yeni tasarım dosyası eklendi"
# Push sırasında LFS dosyaları ayrıca yüklenir
git push origin main
Push çıktısında LFS transferini göreceksiniz:
Uploading LFS objects: 100% (1/1), 45 MB | 2.1 MB/s, done.
Hangi dosyaların LFS kapsamında olduğunu görmek için:
git lfs ls-files
Belirli bir dosyanın LFS pointer’ını incelemek için:
git lfs pointer --file=assets/tasarim-dosyasi.psd
Çıktı şöyle görünür:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 45234567
Clone ve Pull Davranışı
Varsayılan olarak git clone veya git pull yaptığınızda LFS dosyaları da indirilir. Ama bazen sadece kod tarihine bakmak istiyorsunuz, büyük dosyaları indirmek istemiyorsunuzdur.
# LFS dosyalarını indirmeden clone
GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/org/repo.git
# Sonradan ihtiyaç duyulan dosyaları çek
git lfs pull
# Sadece belirli dosyaları çek
git lfs pull --include="assets/logo.psd"
# Belirli dizini hariç tut
git lfs pull --exclude="assets/video/**"
CI/CD ortamlarında bu özellik çok işe yarıyor. Test pipeline’ı büyük video dosyalarına ihtiyaç duymuyorsa, build sürenizi ciddi şekilde kısaltabilirsiniz.
Depolama ve Bant Genişliği Yönetimi
GitHub’da LFS kullanıyorsanız ücretsiz planda 1GB depolama ve ayda 1GB bant genişliği hakkınız var. Bu limitleri aşmak ekstra ücret demek. GitLab da benzer kota sistemi uyguluyor.
Kendi sunucunuzda self-hosted LFS çalıştırmak için birkaç seçenek var:
Gitea ile: Gitea yerleşik LFS desteğiyle geliyor, sadece konfigürasyon dosyasında aktif etmeniz yeterli.
MinIO ile özel LFS sunucusu: Eğer S3-uyumlu bir depolama alanınız varsa, lfs-folly veya rudolfs gibi araçlarla kendi LFS backend’inizi kurabilirsiniz. Bu yaklaşım özellikle büyük ekiplerde veya on-premise ortamlarda maliyet açısından çok daha avantajlı.
# LFS dosyalarını temizleme (eski versiyonları sil)
git lfs prune
# Ne silineceğini önce gör
git lfs prune --dry-run
# Uzak sunucudaki LFS nesnelerini de temizle
git lfs prune --remote
git lfs prune komutu, artık hiçbir branch veya tag tarafından referans edilmeyen LFS nesnelerini temizler. Bunu periyodik olarak çalıştırmak iyi bir pratik.
Gerçek Dünya Senaryosu: Oyun Geliştirme Projesi
Bir süre önce bir oyun stüdyosuyla çalıştım. Unity projelerinde texture’lar, ses dosyaları ve animasyonlar repository’yi mahvediyordu. Uyguladığımız yapı şöyleydi:
# Unity projesi için LFS konfigürasyonu
git lfs track "*.png"
git lfs track "*.jpg"
git lfs track "*.tga"
git lfs track "*.psd"
git lfs track "*.fbx"
git lfs track "*.wav"
git lfs track "*.mp3"
git lfs track "*.aiff"
git lfs track "*.ogg"
git lfs track "*.anim"
git lfs track "Assets/StreamingAssets/**"
# Boyut sınırı olmaksızın bu türleri takip et
git lfs track "*.unitypackage"
Bu yapılandırmadan sonra repository boyutu 8GB’dan 200MB’ın altına düştü. Clone süreleri 45 dakikadan 3 dakikaya indi. Ekip mutlu, server mutlu, herkes mutlu.
Sık Karşılaşılan Sorunlar
“Pointer file” hatası: LFS kurulu olmayan bir makineye clone ettiyseniz, LFS dosyaları içerik yerine pointer metni olarak görünür. Çözüm basit: git lfs install ardından git lfs pull.
Push limiti aşıldı: GitHub veya GitLab’da bant genişliği limitine çarptıysanız, LFS nesnelerini başka bir depolama alanına taşıyabilirsiniz. git lfs fetch ile nesneleri çekip, remote’u değiştirip tekrar push edebilirsiniz.
Lock çakışmaları: LFS, binary dosyalar için kilitleme mekanizması sunuyor. Birden fazla kişi aynı dosyayı değiştirirse merge konflikti çözülemez çünkü binary dosyalar merge edilemiyor.
# Dosyayı kilitle
git lfs lock assets/ana-karakter.psd
# Kilitleri listele
git lfs locks
# Kilidi aç
git lfs unlock assets/ana-karakter.psd
# Başkasının kilidini zorla aç (yönetici yetkisi gerekli)
git lfs unlock --force assets/ana-karakter.psd
Bu özelliği kullanmak için lfsconfig dosyanızda lockable olarak işaretlemeniz gerekiyor:
git lfs track --lockable "*.psd"
Bu satır .gitattributes dosyasına lockable bayrağını ekler.
LFS ile .gitignore İlişkisi
Önemli bir nokta: LFS tracking ile .gitignore birbirinden bağımsız çalışır. Bir dosya hem .gitattributes‘ta LFS ile işaretli hem de .gitignore‘da olabilir; bu durumda .gitignore öncelik alır ve dosya Git tarafından hiç takip edilmez.
Şöyle bir senaryo sık karşılaştım: Geliştirici dosyayı LFS’e ekledi ama .gitignore‘da da o pattern vardı. Dosya hiç commit edilmedi, neden LFS’te görünmüyor diye saatlerce uğraştık.
# Bir dosyanın neden takip edilmediğini anlamak için
git check-ignore -v buyuk-dosya.zip
# LFS tracking durumunu kontrol et
git lfs track | grep zip
CI/CD Entegrasyonu
GitHub Actions ile LFS dosyalarını çekmek için actions/checkout action’ının LFS desteği mevcut:
- uses: actions/checkout@v4
with:
lfs: true
GitLab CI’da ise runner konfigürasyonunda LFS desteği aktif edilmeli. .gitlab-ci.yml dosyanızda:
variables:
GIT_LFS_SKIP_SMUDGE: "1" # LFS dosyalarını atla
before_script:
- git lfs pull --include="assets/required/**" # Sadece gerekli dosyaları çek
Bu yaklaşım CI sürenizi önemli ölçüde kısaltır. Tüm LFS içeriğini her build’de çekmeye gerek yok, sadece o build için gerekli olanları alın.
LFS Performans İpuçları
Büyük repo’larda LFS operasyonlarını hızlandırmak için birkaç konfigürasyon ayarı:
# Paralel upload/download sayısını artır
git config lfs.concurrenttransfers 8
# Batch transfer boyutunu artır (varsayılan 100)
git config lfs.fetchrecentrefsdays 7
# Yakın zamanda kullanılan branch'lerin LFS nesnelerini ön belleğe al
git config lfs.fetchrecentcommitsdays 3
Bu ayarları global olarak yapmak için --global bayrağını ekleyin. CI agent’larında proje bazlı tutmak daha iyi olabilir.
Transfer sorunlarını debug etmek için:
# Ayrıntılı LFS log çıktısı
GIT_TRACE=1 GIT_TRANSFER_TRACE=1 git lfs push origin main 2>&1 | head -100
Sonuç
Git LFS, doğru kullanıldığında ciddi bir ağrı kesici. Ama “her büyük dosyayı LFS’e at, sorun biter” şeklinde yaklaşmak doğru değil. Önce hangi dosyaların neden büyük olduğunu anlamak, sonra LFS’in gerçekten doğru araç olup olmadığına karar vermek gerekiyor.
Alternatifler de göz önünde bulundurun: Artifact repository’leri (Artifactory, Nexus) build çıktıları için genellikle daha uygun. Docker image’ları için Registry kullanmak LFS’ten çok daha mantıklı. Veri setleri için DVC (Data Version Control) düşünebilirsiniz, özellikle ML ekipleri için.
Ama tasarım dosyaları, ses varlıkları, test fixture’ları ve benzeri dosyalar için Git LFS hala en pratik çözüm. Kurulumu basit, git workflow’unu bozmayan ve geniş platform desteği olan bir araç. Repository’niz şişmeye başladıysa, git lfs migrate info ile başlayın, ne kadar kazanacağınızı görün ve karar verin.
