13 puan yazan GN⁺ 2025-08-16 | 1 yorum | WhatsApp'ta paylaş
  • Git projesi kısa süre önce büyük dosya yönetimi sorununu doğrudan çözmeye resmen başladı
  • Git LFS, kullanıcılar için çeşitli maliyetler ve vendor lock-in gibi sorunlar yaratan geçici bir çözüm
  • Son dönemde gelen partial clone özelliği sayesinde, yalnızca Git kullanarak LFS’nin rolünün büyük kısmını ikame etmek mümkün hale geldi
  • İleride large object promisor adlı yeni bir çözümün de resmi Git’e entegre edilmesi hazırlanıyor
  • Bu değişimlerle birlikte, büyük dosya yönetiminin nihai çözümünün harici eklentiler değil, Git’in kendisi olması bekleniyor

Git’in büyük dosya sorunu ve değişim

  • Git’in en büyük düşmanı tam da büyük dosyalar olabilir
  • Büyük dosyalar Git deposunu şişirir, git clone hızını düşürür ve çoğu hosting ortamını da olumsuz etkiler

Git LFS’nin ortaya çıkışı ve sınırları

  • 2015’te GitHub, büyük dosya sorununu aşmak için Git LFS’yi yayınladı
  • Ancak Git LFS de kendi başına yeni karmaşıklık ve ek depolama maliyetleri getirir
  • Git topluluğu uzun süredir büyük dosya sorununu kökten nasıl çözeceğini sessizce düşünüyordu; son resmi Git sürümlerinde ise LFS olmadan büyük dosyaları yönetmeye yönelik yeni bir yön ortaya kondu

Bugün hemen uygulanabilecek yöntem: Git LFS’yi partial clone ile değiştirmek

  • partial clone’un çalışma mantığı

    • Git LFS: Büyük dosyalar depo dışında tutulur ve çalışma sırasında yalnızca gerekli dosyalar indirilir
    • Git partial clone (2017’de eklendi):
      • --filter seçeneğiyle belirli boyutun üzerindeki blob’lar hariç tutularak kopyalama yapılır
      • Yalnızca gerektiğinde ilgili büyük dosya sunucudan indirilir

      Partial clone kullanıldığında Clone ve Fetch sırasında [büyük ikili varlıkları] önceden indirmek gerekmez; bu da indirme süresini ve disk kullanımını azaltabilir

  • partial clone ile LFS’nin ortak yönleri

    • 1. Checkout boyutunu en aza indirme: Yalnızca en güncel sürüm alınır, tüm dosya geçmişi atlanır
    • 2. Hızlı klonlama: Büyük dosyalar aktarılmadığı için clone daha hızlıdır
    • 3. Hızlı kurulum: shallow clone’dan farklı olarak tüm proje geçmişine erişim mümkündür
  • partial clone kullanım örneği

    • Geçmişinde çok sayıda büyük PNG dosyası bulunan bir repo’nun klonlama süresi ve disk kullanımı örneği:
      • Normal clone ile neredeyse 4 dakika sürüyor ve 1.3GB yer kaplıyor
      • partial clone ve 100KB blob sınırı uygulandığında 6 saniyede klonlanıyor ve 49MB yer kaplıyor
      • Orijinale göre klonlama hızı %97 iyileşiyor, checkout boyutu %96 küçülüyor
  • partial clone’un sınırları

    • Filtrelenen veriye ihtiyaç duyulduğunda (ör. git diff, git blame, git checkout) Git sunucudan dosyayı ister
    • Bu, Git LFS ile aynı özelliktir
    • Pratikte ikili dosyalarda blame çalıştırma ihtiyacı nadirdir

Git LFS’nin sorunları

  • Yüksek vendor lock-in: GitHub uygulaması yalnızca kendi sunucularını destekler; bu da ücretlendirme ve bağımlılık yaratır
  • Maliyet sorunu: 50GB depolamada GitHub LFS yıllık $40, Amazon S3 ise $13
  • Geri dönüşün zorluğu: Bir kez LFS’ye geçildiğinde, geçmiş yeniden yazılmadan eski hâle dönmek mümkün değildir
  • Sürekli kurulum maliyeti: Tüm ekip üyelerinin LFS kurması gerekir; kurulmadığında dosya yerine metadata dosyaları görülür ve bu da kafa karışıklığı yaratır

İleriye dönük görünüm: Large Object Promisor

  • Büyük dosyalar hosting platformları (GitHub, GitLab) için de maliyet sorunu yaratır
  • Git LFS, büyük dosyaları CDN’e offload ederek sunucu maliyetlerini azaltır
  • Large Object Promisor nedir?

    • Git bu yılın başında large object promisor adlı özelliği resmen merge etti
    • Bu özellik, LFS’ye benzer şekilde sunucu tarafındaki depo yükünü azaltırken kullanıcı tarafındaki karmaşıklığı büyük ölçüde düşürür

      Bu çabanın amacı, özellikle zaten ikili biçimde sıkıştırılmış büyük blob’larla ilgili sunucu tarafı işlemlerini iyileştirmektir
      Git LFS’ye alternatif bir çözümdür
      Large Object Promisors, git-scm.com

  • Nasıl çalışır?

    • 1. Kullanıcı büyük dosyayı Git host’una push eder
    • 2. Host, büyük dosyayı arka uçtaki promisor’a offload eder
    • 3. clone sırasında Git host’u istemciye promisor bilgisini verir
    • 4. İstemci gerekirse ilgili promisor’dan büyük dosyayı otomatik olarak alır
  • Güncel durum ve zorluklar

    • Büyük nesne promisor’u hâlâ geliştirme aşamasında; Mart 2025’te kodun bir kısmı Git’e merge edildi
    • GitLab gibi platformlarda ek implementasyonlar ve çözülmemiş konular üzerine tartışmalar sürüyor
    • Yaygın kullanıma geçmesi için hâlâ zamana ihtiyaç var
    • Yakın vadede büyük dosya depolamada Git LFS’ye bağımlılık kaçınılmaz görünüyor
    • promisor yaygınlaştığında GitHub’a 100MB üzeri dosya yüklemek de mümkün hale gelebilir

Sonuç: Git’te büyük dosyaların geleceği Git

  • Git projesi, büyük dosya sorununu sizin yerinize durmaksızın düşünüyor
  • Şu anda hâlâ Git LFS kullanımı gerekiyor
  • Ancak partial clone ve large object promisors geliştikçe Git LFS giderek gereksiz hale gelecek; çok yakında büyük dosyaları yalnızca Git ile kolayca yönetmek mümkün olacak
  • Gelecekte MP3 kütüphanesini Git’e koyma fikrinin kendisi, büyük ölçekli kullanımın önündeki son engel olabilir

1 yorum

 
GN⁺ 2025-08-16
Hacker News görüşleri
  • Eskiden svn bile, çok sayıda büyük ikili dosya içeren 150GB’lık bir çalışma dizininde büyük sorunlar olmadan gayet iyi çalışıyordu; buna karşılık git böyle değil. svn’in büyük ikili dosyalar konusunda neden git’ten farklı bir yaklaşım izlediğini, git’in neden aynı şeyi yapamadığını merak ediyorum. Ayrıca ikili verilerle çalışırken mutlaka gereken özellik dosya kilitlemedir; belirli bir dosyada yalnızca bir kişinin çalışıp diğerlerinin salt okunur olması, karmaşık merge sorunlarını önleyebilir. Büyük dosyaları dışarıya offload etmenin gerçek performans ya da kararlılık sorunlarını gerçekten iyileştirip iyileştirmediğini de pek anlayamıyorum. Sonuçta depo farklı olsa da yine depodur. Offload işi aslında public git forge’ların büyük dosya depolama maliyetinden kaçınma yöntemi gibi görünüyor

    • git ve svn tamamen farklı tasarımlar. git tamamen dağıtık olduğu için her deponun tüm dosyaların tam geçmişini taşıması gerekir ve kilit kavramı anlamsızdır. Projeye uygun sürüm kontrol sistemini seçmek yeterli; git’in her şey için uygun olması gerekmiyor
  • Large object promisor kavramı hoşuma gidiyor. S3 gibi bir yere kolayca bağlayıp kullanmak mümkün olursa mevcut LFS’ten hemen geçerim gibi geliyor. S3, büyük ikili dosyaları sürüm kontrolünde tutarken iyi bir sinerji sağlıyor. Intelligent Tiering sayesinde veri yaşlandıkça otomatik olarak daha ucuz depolama katmanlarına taşınması da avantaj. 10 yıllık veriyi geri yüklemek yarım gün sürse bile sorun değil

    • Ben de aynı fikirdeyim. Bunun neden en başından beri varsayılan yöntem olmadığını anlayamıyorum. Küçük bir git LFS sunucusunu kendim işletiyorum ve git yalnızca S3’ü native desteklese hemen geçmeye hazırım

    • Şu an iş yerinde maliyeti düşürmek için LFS nesnelerini bucket’ta cache’liyoruz. Her PR çalıştırıldığında git lfs ls-files ile dosya listesini alıyor, gcp’den çekiyor, git lfs checkout ile nesneleri lokalde saklıyor, sonra pull ile yalnızca eksik kalanları alıyoruz. Cache’lenmemiş dosyalar gcloud storage rsync ile tekrar bucket’a yükleniyor. Geliştirici açısından ek ayar gerekmiyor; sadece yeni nesneler pull ediliyor ve GitHub UI da depo durumu konusunda kafa karıştırmıyor. Eskiden LFS backend’i kendimiz mi kursak diye düşünmüştüm ama bu yöntem şu anki en büyük sorunumuzu çözüyor. GitHub, CI sırasında LFS dosyaları her alındığında aşırı trafik ücreti çıkarıyordu; ayrıca 10GB cache sınırı ve branch’ler arasında paylaşım olmaması nedeniyle her seferinde yeniden indirmek gerekiyordu. Cache kapasitesini para verip artırmak isterdim ama bunun da bir yolu yoktu. Bunu geliştiricilere uygulamak da yalnızca bir git hook eklemek kadar basit

    • S3’ün Amazon’la ilgili bir servis olup olmadığını merak ediyorum

  • Git LFS hakkında çeşitli olumsuz noktalardan söz edilse de vendor lock-in olduğu görüşüne katılmıyorum. GitHub açık istemci ve sunucu sağladığı için bu iddia haksız. Yine de LFS, offline/sneakernet kullanımında çalışmıyor; bu yaygın bir durum olmasa da anılmaya değer. large object promisor, LFS’nin istemci tarafı karmaşıklığını sunucuya taşımış gibi görünüyor; sonuçta sadece karmaşıklığın yeri değişmiş oluyor. Eğer yapı, git sunucusunun dosyaları LFS sunucusuna ve nesne deposuna yüklemesi şeklindeyse farklı trade-off’lar ortaya çıkar. Public git sunucularında promisor remote gizli tutulursa upload sırasında ne olacağını merak ediyorum

    • Bence LFS gerçekten kötü. Sunucu implementasyonu da dağınık ve nesne içeriğiyle depolama yöntemini birbirine karıştırıyor. Opt-in yöntemi de çok kötü; düşünmeden kullanırsan aslında istediğin dosya yerine sadece küçük bir metin dosyası elde ediyorsun. Yeni çözümün daha iyi olup olmadığını bilmiyorum ama LFS’nin iyi olmadığı açık

    • Yakın zamanda öğrendiğim başka bir Git LFS sorunu da, migration’ın üst commit’lerdeki .gitattributes dosyalarını da kirletmesi. Yani commit sırası A→B→C ise ve büyük dosya yalnızca C’de LFS’ye eklendiyse, A ve B’de de var olmayan LFS dosyalarına işaret eden .gitattributes oluşuyor. Çünkü migration sırasında .gitattributes, geçmiş boyunca geriye doğru yayılıyor ve mevcut commit’te dosyanın gerçekten var olup olmadığına bakmıyor

    • Eskiden Git LFS SSH desteklemiyordu; bu yüzden mutlaka SSL sertifikası almak gerekiyordu ve bu da evde self-host eden kullanıcılar için giriş bariyeriydi. GitLab yakın zamanda SSH desteği yaması eklemiş gibi görünüyor

  • Yazılım mühendisliği dersinde, büyük dosyaları (medya vb.) Git’e koymak yerine artifact deposuna (Artifactory vb.) koymamız önerilmişti. Böylece snapshot dependency biçiminde dağıtılabilir ve build sistemi yalnızca en güncel sürümü alacak şekilde yönetilebilir. Ekip arkadaşlarının lokalde biriken eski dosyaları da build sistemi cache’ini temizleyerek hemen kaldırılabilir

    • Bu yaklaşım biraz git submodule gibi duruyor. Eğer submodule bu sorunu çözseydi insanlar zaten kullanırdı. git submodule da shallow clone destekliyor (ilgili bağlantı: https://stackoverflow.com/questions/2144406/how-to-make-shallow-git-submodules). Ben büyük dosya sorununu hiç yaşamadım; bu yöntem neden işe yaramıyor olabilir merak ediyorum. SO’daki dezavantajlar bana çok büyük görünmüyor

    • Derste CI/CD sistem mimarisinin de öğretilip öğretilmediğini merak ediyorum. Günümüzde yeni mühendisler GitLab, Artifactory, CodeSonar, Anchore gibi araçlarla entegre çalışan genel yapıya pek hakim değil

    • Bu yöntemin de dezavantajları var. CI/CD sistemi ya da geliştiriciler için ek kimlik bilgileri gerekiyor. Commit süreci de birden çok adıma çıkıyor; önce artifact ID’yi bilmek gerekiyor ve bunu otomatikleştirmek için git hook kullanmaya başlayınca sonunda git-lfs kadar karmaşık hale geliyor

  • Bu yazı LFS’yi haksız değerlendiriyor. LFS, GitHub’a bağımlı değil ve protokolü de açık. LFS’nin dezavantajları, git eklentisi olmasının kaçınılmaz sonucu; promisor’lar da aslında LFS ile aynı fikir. Sadece git’in içine gömülünce UX biraz daha iyi oluyor

    • LFS kullanmış bir depo bir kez bunu yaptı mı kalıcı olarak lock-in oluyor. Kullanılan alanı azaltmak için deponun kendisini silmek gerekiyor ve bu da resmî olarak açık şekilde belirtilmiyor. Şirketimizin GitHub istatistiklerini incelerken büyük sıkıştırılmış DB dosyalarını LFS’ye koyduğumuzda bunu bizzat yaşadım
  • Bu gerçek çözüm değil. git LFS de sadece geçici bir çözüm ve clone sırasında filtre argümanı vermek de temel sorunu çözmüyor. git clone, her kullanıcının öğrendiği ilk komutlardan biri; ama burada her seferinde filtreyi hatırlamak gerekiyor. Unutulursa sadece zaman kaybediliyor, doğru yapılsa bile clone edilen depo düzgün çalışmayabilir. Sonuçta rsync gibi en güncel dosyaları önce verimli şekilde alan bir yapıya geçmek gerekiyor ki sorun kökten çözülsün. git bu tür köklü değişiklikleri pek yapmıyor

    • Kesinlikle katılıyorum. git sorunları hep bir flag daha ekleyerek “çözüyor”, ama kullanıcıların çoğu bu özelliklerin farkında bile değil. Varsayılanları iyileştirmek, uyumluluğu bozmadan da bu sorunları çözebilir

    • clone edilen depo düzgün çalışmayabilir
      Aslında eksik olan yalnızca blob geçmişi

    • rsync’in çözdüğü söyleniyor ama bunun pratikte nasıl göründüğünü soruyorum. Algoritmayı değil, kullanıcının git clone yaptığında yerel dosya sisteminde tam olarak ne oluşacağını merak ediyorum

    • Eğer depo boyutunun çoğu geçmiş revizyonlardaysa, rsync benzeri şekilde önce yalnızca en güncel sürümü almak çoğu kullanıcı için en uygun çözüm olur

  • Git çekirdeğine büyük dosya desteği eklenmesine çok seviniyorum. Dış çözüm olsa bile sonuçta yine benzer bir opt-in yapısı ortaya çıkıyor. Komut sayısını olabildiğince azaltıp süreci seamless hale getirmek istediğim için API’yi .gitattributes dosyasındaki smudge/clean filtreleriyle sınırlı tasarladım. Ayrıca vendor lock-in’i ortadan kaldırmak için Atlassian ve Microsoft ile doğrudan çalıştım; dosya kilitleme API’sinde de Atlassian’dan büyük destek alındı. LFS, üç farklı host üzerinde uyumlu destek sunan açık kaynak bir çözüm olarak sağlanıyor

  • Biz de git veya git-lfs’de yaşadığımız sorunları çözmek için oxen geliştiriyoruz. git arayüzünü aynen korurken büyük dosyalar ve milyonlarca dosya içeren monorepo ortamlarında çok daha hızlı çalışıyor. Açık kaynak CLI ve sunucu sunuyoruz; ilgilenirseniz geri bildirim duymak isteriz
    https://github.com/Oxen-AI/Oxen

  • git’in depolama biçiminin kendisinin de restic veya borg gibi modern yedekleme araçlarında olduğu gibi dosya ve dizinler için content-defined chunking temelli şekilde baştan ele alınması gerekiyor

  • GitLFS’nin eksilerinden biri olarak kimlik doğrulama sorunu da atlanmış; SSH-agent kullanılmazsa tek bir push sırasında bile birden fazla kez kimlik doğrulama gerekebiliyor. Kendi deneyimime göre bunu iki ya da üç defadan fazla yaşadığım bile oldu