Git LFS: büyük dosyalar Git repository'sinde nasıl saklanır?
Git LFS (Large File Storage), büyük ikili dosyaları ayrı bir sunucuda saklayan ve repository'ye yalnızca küçük işaretçi dosyalar koyan bir Git eklentisidir. Clone işlemi hızlanır, geçmiş şişmez ve dosyalarla çalışmak alışıldığı gibi kalır: git add, commit ve push.
Git LFS nedir ve neden gerekir?
Git LFS (Large File Storage), büyük dosyaları saklamak için resmi bir Git eklentisidir: videolar, PSD tasarımları, veri setleri, sinir ağı modelleri, oyun asset'leri. Commit'e dosyanın kendisi yerine yaklaşık 130 baytlık bir metin işaretçisi girer, içerik ise sunucudaki ayrı bir LFS deposuna gider. Checkout sırasında eklenti gerçek dosyayı çalışma dizinine koyar; bu yüzden sizin için her şey sıradan Git gibi görünür.
Git LFS'in çözdüğü sorun, Git'in yapısından kaynaklanır. Her dosyanın her sürümü geçmişte sonsuza dek kalır ve clone sırasında tüm geçmiş bütünüyle indirilir. 200 MB'lık bir videoyu on kez değiştirdiyseniz repository şimdiden yaklaşık 2 GB tutar ve her yeni geliştirici yalnızca sonuncusuna ihtiyaç duysa bile on sürümün hepsini indirir. Metin için iyi çalışan sıkıştırma ve delta'lar ikili dosyalarda neredeyse işe yaramaz.
LFS ile clone sırasında büyük dosyaların yalnızca mevcut commit'e ait sürümleri indirilir. Eski sürümler sunucuda durur ve eski bir commit'e geçtiğinizde çekilir.
Git LFS içeride nasıl çalışır?
Mekanizma Git filtrelerine — clean ve smudge — dayanır. LFS'in takip ettiği bir dosyayı git add ile eklediğinizde clean filtresi devreye girer: içeriği yerel önbelleğe (.git/lfs/objects) koyar ve index'e işaretçiyi aktarır. Checkout sırasında smudge filtresi tersini yapar: nesneyi hash'e göre önbellekte bulur (ya da sunucudan indirir) ve gerçek dosyayı yazar.
İşaretçi şöyle görünür:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 209715200
Üç satır: spesifikasyon sürümü, içeriğin SHA-256'sı ve bayt cinsinden boyut. Git geçmişinde saklanan tam olarak budur, bu yüzden geçmiş hafif kalır. git push sırasında bir pre-push hook çalışır: önce yeni nesneler LFS API üzerinden yüklenir, ardından commit'ler normal protokolle gönderilir.
Hangi dosyaların LFS'e verileceğini repository kökündeki .gitattributes dosyası belirler. Kodla birlikte commit edilir, bu yüzden kurallar tüm ekip için aynıdır.
Git LFS nasıl kurulur?
Windows için Git'te eklenti zaten kurulum paketine dahildir. macOS ve Linux'ta paket olarak kurulur:
# macOS (Homebrew)
brew install git-lfs
# Debian / Ubuntu
sudo apt install git-lfs
# Fedora
sudo dnf install git-lfs
Kurulumdan sonra kullanıcı başına bir kez şunu çalıştırın:
git lfs install
Komut LFS filtrelerini global ~/.gitconfig'e yazar ve içindeyseniz mevcut repository'ye hook'ları kurar. Her şeyin yerinde olduğunu git lfs version ile kontrol edebilirsiniz; ayrıntılı yapılandırmayı (sunucu adresi, önbellek yolları) git lfs env gösterir.
Büyük dosyaları takip etmeye nasıl başlanır: git lfs track
Yeni bir proje için tipik senaryo:
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "models/**"
git add .gitattributes
git add design/banner.psd
git commit -m "Banner tasarımını LFS ile ekle"
git push origin main
Desenin etrafındaki tırnaklar zorunludur: onlar olmadan shell *.psd'yi mevcut klasördeki dosyaların listesine kendisi açar ve kural yanlış olur. git lfs track'ten sonra .gitattributes'ta şu satır belirir:
*.psd filter=lfs diff=lfs merge=lfs -text
-text özniteliği, ikili dosyayı bozacak satır sonu dönüşümünü kapatır. Sıra önemlidir: önce track kuralı, sonra dosyanın git add'i. Dosya kural oluşmadan önce normal şekilde eklendiyse, geçmişte sıradan bir blob olarak kalmıştır.
Dosyanın gerçekten LFS'te olduğu nasıl kontrol edilir?
git lfs ls-files
4d7a214614 * design/banner.psd
9c1e0b7a3f * video/intro.mp4
git lfs status
git lfs ls-files, mevcut commit'te LFS'te saklanan dosyaları gösterir. Yıldız içeriğin indirildiği, tire ise çalışma kopyasında yalnızca işaretçi bulunduğu anlamına gelir. Takip desenlerinin listesini argümansız git lfs track yazdırır; bir kuralı git lfs untrack "*.psd" ile kaldırabilirsiniz.
Clone ve dosyaların alınması
Normal git clone, LFS ile şeffaf biçimde çalışır: eklenti kuruluysa büyük dosyalar otomatik olarak indirilir. Ama bir iş arkadaşınızda LFS kurulu değilse çalışma kopyasında resimler yerine metin işaretçileri görür; bu, «PSD yerine bir tür metin var» belirtisinin en yaygın nedenidir. Çözüm kurulum ve şu komuttur:
git lfs install
git lfs pull
git lfs pull, mevcut commit'in nesnelerini indirip çalışma dizinine yerleştirir. Ayrıca git lfs fetch vardır; dosyalara dokunmadan yalnızca önbelleğe indirir. --all bayrağıyla tüm referansların nesnelerini indirir; bu, tam yedek almak veya başka bir sunucuya taşımak için kullanışlıdır.
Büyük dosyalar olmadan nasıl clone yapılır?
CI'da ya da yalnızca kod gerektiğinde gigabaytlarca asset indirmek gereksizdir. Bir ortam değişkeni smudge filtresini kapatır:
GIT_LFS_SKIP_SMUDGE=1 git clone https://example.com/team/game.git
cd game
git lfs pull --include="textures/ui/**"
Repository işaretçilerle clone'lanır, ardından gerekli dosyaları --include ile seçerek alırsınız (--exclude da vardır). Bu, pipeline'lardaki build'leri belirgin şekilde hızlandırır.
Mevcut dosyalar Git LFS'e nasıl taşınır: git lfs migrate
Sık karşılaşılan durum: repository zaten şişmiş, büyük dosyalar geçmişte duruyor. git lfs track komutu geçmişe etki etmez, yalnızca yeni commit'leri etkiler. Geçmişi yeniden yazmak için git lfs migrate kullanın.
Önce yeri neyin kapladığını değerlendirin:
git lfs migrate info --everything --top=10
Ardından gerekli türleri tüm branch'lerde taşıyın:
git lfs migrate import --include="*.psd,*.mp4" --everything
git push --force --all
git push --force --tags
Migration, bu dosyaların geçtiği her commit'i yeniden yazar; yani tüm hash'ler değişir. Bu, yayınlanmış branch'lerin rebase'iyle aynı durumdur: tüm katılımcılar uyarılmalı, force push'tan sonra repository'yi yeniden clone'lamalı ya da branch'lerini hard reset ile sıfırlamalıdır. Migration'dan önce yedek alın (git clone --mirror).
Geçmişi yeniden yazmak mümkün değilse daha yumuşak bir seçenek var: git lfs migrate import --no-rewrite dosya/yolu. Bu, dosyaları o andan itibaren LFS'e geçiren yeni bir commit oluşturur. Eski sürümler geçmişte kalır, ama repository'nin büyümesi durur.
Dosya kilitleme: ikili dosyalarda çakışmalara karşı koruma
İki tasarımcı aynı PSD'yi düzenliyor ve Git değişikliklerini birleştiremiyor; işlerden biri kaybolacak. Bu tür dosyalar için LFS'te kilitler vardır. Türü kilitlenebilir olarak işaretlersiniz:
git lfs track "*.psd" --lockable
.gitattributes'a lockable özniteliği eklenir ve bu dosyalar siz kilitleyene kadar çalışma kopyasında salt okunur olur:
git lfs lock design/banner.psd
git lfs locks
design/banner.psd anna ID:123
# değişiklikleri push ettikten sonra
git lfs unlock design/banner.psd
Dosya kilitliyken başka birinin ona ait değişiklikleri push etmesi reddedilir. Kilitleri sunucu destekler; bu yüzden büyük Git hosting'lerinde çalışırlar, ama kendi yazdığınız bir sunucuda olmayabilirler. Yönetici, başkasının kilidini git lfs unlock --force ile kaldırabilir.
LFS nesneleri nerede saklanır ve maliyeti ne olur?
LFS nesneleri, LFS API'yi destekleyen bir sunucuda yaşar. Bunu popüler Git hosting'leri ve self-hosted çözümler ile ayrı sunucular uygular. Bulut hosting'lerinde LFS depolama alanı ve trafiği için limitler vardır ve bunlar hizmete ve plana göre değişir; yüzlerce gigabaytlık veri setlerini koymadan önce platformunuzun güncel koşullarını kontrol edin.
Trafiğin her indirmede sayıldığını unutmayın: her commit'te LFS dosyalı repository'yi clone'layan bir CI, limiti insanlardan daha hızlı tüketebilir. .git/lfs'i build'ler arasında önbelleğe alın veya GIT_LFS_SKIP_SMUDGE kullanın.
Yerel önbellek de büyür. git lfs prune komutu, sunucuda zaten bulunan ve mevcut ve yakın tarihli commit'ler için gerekmeyen eski nesneleri siler.
Git LFS ne zaman uygundur, ne zaman değildir?
| Durum | LFS uygun mu? | Yorum |
|---|---|---|
| Oyun asset'leri, tasarımlar, ses, video | Evet | Klasik durum: sık değişen ikili dosyalar |
| Kodun yanındaki ML modelleri ve orta boy veri setleri | Evet, kotalara dikkat ederek | Çok büyük veriler için özel veri sürümleme araçları daha uygundur |
| Derlenmiş build çıktıları | Hayır | Yerleri Git değil, artifact registry veya release'lerdir |
| Bağımlılıklar (node_modules, vendor) | Hayır | Paket yöneticisiyle kurulur, .gitignore'a ekleyin |
| Büyük metin dosyaları (SQL dump'ları, CSV) | Duruma bağlı | Git metni delta'larla verimli saklar; dosyalar devasa ve diff'te pek okunmuyorsa LFS gerekir |
| Gizli bilgiler ve özel anahtarlar | Asla | LFS verileri şifrelemez, bir secret deposu değildir |
Sık yapılan hatalar ve çözümleri
Çalışma kopyasında dosya yerine metin işaretçisi var
LFS kurulu değil ya da clone GIT_LFS_SKIP_SMUDGE=1 ile yapılmış. git lfs install ve git lfs pull çalıştırın.
Dosya LFS'i atlayarak geçmişe girdi
Track kuralı git add'den sonra eklendi. Commit henüz gönderilmediyse dosyayı index'ten çıkarın (git rm --cached dosya), kuralın .gitattributes'ta olduğundan emin olun ve yeniden ekleyin. Zaten gönderildiyse git lfs migrate import kullanın. Bu tür dosyaları bulmak için git lfs fsck --pointers yardımcı olur.
Push dosya boyutu nedeniyle reddediliyor
Birçok hosting, sıradan Git'te tek bir nesnenin boyutunu sınırlar. «this exceeds the file size limit» gibi bir mesaj, dosyanın LFS'e verilmesi gerektiği anlamına gelir. Son commit'i veya geçmişi yukarıda anlatıldığı gibi yeniden yazın; basit bir «dosyayı sil» commit'i işe yaramaz, dosya önceki commit'lerde kalır.
git lfs migrate'ten sonra iş arkadaşlarında her şey bozuldu
Yerel branch'leri eski hash'lere dayanıyor. En güvenilir yol repository'yi yeniden clone'lamaktır; push edilmemiş iş varsa cherry-pick ile yeni branch'lere taşıyın.
Git LFS komutları kopya kağıdı
| Komut | Ne yapar |
|---|---|
git lfs install | Filtreleri ve hook'ları ayarlar |
git lfs track "*.ext" | Deseni .gitattributes'a ekler |
git lfs untrack "*.ext" | Deseni kaldırır |
git lfs ls-files | Mevcut commit'te LFS'teki dosyalar |
git lfs pull | Nesneleri indirip yerleştirir |
git lfs fetch --all | Tüm referansların nesnelerini önbelleğe indirir |
git lfs migrate import --include="..." --everything | Dosyaları geçmişten LFS'e taşır |
git lfs lock / unlock / locks | Kilitlerle çalışma |
git lfs prune | Yerel önbelleği eski nesnelerden temizler |
git lfs env | Ayarların tanılanması |
Özet
Git LFS, büyük ikili dosyaları geçmişten ayrı bir depoya çıkarır ve commit'lerde hafif işaretçiler bırakır. Ana kural: büyük dosyaların ilk commit'inden önce git lfs track'i ayarlamak, .gitattributes'ı commit etmek ve hosting kotalarını izlemek. Dosyalar zaten geçmişteyse git lfs migrate yardımcı olur, ama bu tüm sonuçlarıyla birlikte geçmişin yeniden yazılmasıdır. Geçmişle çalışmayı, rebase'i ve Git'in diğer ileri düzey araçlarını Git kursunda uygulamalı olarak ele alıyoruz.
Sık sorulan sorular
Git LFS ücretsiz mi?
Eklentinin kendisi açık kaynaklı ve ücretsizdir. Planınızın ücretsiz limitlerini aşarsanız Git hosting'inde depolama ve trafik için ödeme yapmanız gerekebilir.
LFS için hangi dosya boyutu büyük sayılır?
Kesin bir sınır yoktur; genellikle sık değişen, birkaç megabayttan büyük ikili dosyalar LFS'e gönderilir. Büyük boyutlu metin dosyalarını bile Git LFS olmadan verimli saklar.
Git LFS'ten vazgeçip dosyaları sıradan Git'e geri döndürmek mümkün mü?
Evet, geçmişi geri yazan git lfs migrate export --include="*.psd" --everything komutuyla. Ardından kuralları .gitattributes'tan kaldırıp force push yapmanız gerekir.
LFS'teki dosyalar için git diff çalışır mı?
Dosyalar ikili olduğundan Git içeriğin değil, işaretçinin değişimini gösterir. Resimler ve belgeler için karşılaştırma harici araçlarla yapılır.
Ekipteki herkesin LFS'e ihtiyacı var mı?
Evet, aksi halde eklentisi olmayan kişinin çalışma kopyasında dosyalar yerine işaretçiler olur ve commit'leri yanlışlıkla büyük dosyaları LFS'i atlayarak ekleyebilir.
Bu konu “Sıfırdan Güvenilir Geliştiriciye Git” kursunda uygulamalı olarak ayrıntılı işleniyor.
Kursa git