Git LFS for Large Files

Khimananda Oli 7 min read Virtualization
Git LFS for Large Files

By Khimananda Oli | Last reviewed: August 2026

Standard Git repositories degrade rapidly when you commit binaries like datasets, compiled libraries, or high-resolution media directly into history. Implementing Git LFS for large files solves this by replacing heavy objects with lightweight text pointers while storing the actual content on a separate remote server. This approach keeps clone times fast and history manageable without forcing developers to abandon their familiar Git workflow.

How do you correctly configure Git LFS for large files?

Configuration is deceptively simple but requires discipline. A common mistake I see in audits is installing LFS globally but forgetting to verify per-repository hooks, leading to silent failures where multi-gigabyte binaries still enter standard packfiles. Always treat LFS setup as code, not just a local environment preference.

Installation and initialization

Before touching any repository, ensure the client extension is active. On Ubuntu/Debian systems in 2026, the canonical method uses the official APT repository rather than outdated distro packages:

curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sudo apt-get install git-lfs
git lfs install

The final command installs post-checkout and pre-push hooks in your global Git config. For shared team environments, document this step in your onboarding wiki or automate it via Ansible playbooks for developer workstations to guarantee consistency across Nepal-based and remote teams.

Defining tracking rules

Never track everything. Be surgical with patterns in .gitattributes to avoid accidentally capturing temporary build artifacts or IDE caches:

# Track ML model weights and datasets
*.pt filter=lfs diff=lfs merge=lfs -text
*.onnx filter=lfs diff=lfs merge=lfs -text
data/raw/ filter=lfs diff=lfs merge=lfs -text

# Media assets
assets/videos/*.mp4 filter=lfs diff=lfs merge=lfs -text
design//*.psd filter=lfs diff=lfs merge=lfs -text

# Exclude temp files explicitly
!*.tmp
!.cache/

After editing, stage the attributes file immediately: git add .gitattributes. This file must be committed before any LFS-tracked content; otherwise, collaborators cloning the repo will download raw pointers instead of actual files.

Developer Workspacemodel.pt (2.4 GB)Git Staging AreaPointer File (130 B)LFS Object StoreSHA-256 BlobStandard Git RepositoryCommits + .gitattributes + Pointers OnlyCommit metadataGit LFS for large files separates content from history
Git LFS for large files replaces binaries with pointers during staging and uploads actual content separately

How do you migrate an existing repository to Git LFS?

Retrofitting LFS onto a repo that already contains large binaries is the most operationally risky task. Simply adding tracking rules going forward does nothing to shrink existing history. You must rewrite commits, which changes every SHA downstream. Coordinate this carefully with your team and align it with your broader CI/CD pipeline maintenance windows.

Rewriting history safely

Use git lfs migrate in import mode to scan all branches and convert matching files retroactively:

# Dry-run first to inspect what will change
git lfs migrate info --include="*.bin,*.dat" --everything

# Actual migration (irreversible without backup)
git lfs migrate import --include="*.bin,*.dat" --everything \
  --include-ref=refs/heads/main \
  --include-ref=refs/heads/develop

This process can take hours for repositories with years of binary churn. Run it on a fresh clone, never on your primary working copy. After completion, force-push all rewritten branches and require every collaborator to re-clone. There is no safe way to merge rewritten history back into old clones.

Validating migration success

Verify that no large objects remain in standard packfiles:

  • git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectsize)' | awk '/^blob/ {print $2}' | sort -rn | head — confirms largest blobs are now small pointers.
  • git lfs ls-files — lists all currently tracked LFS objects.
  • Clone the migrated repo fresh and time it; expect 70–95% reduction in initial clone duration.

What are the storage limits and costs for Git LFS?

LFS shifts cost from compute/network to dedicated object storage. Pricing models vary dramatically between providers, and exceeding free tiers is the #1 budget surprise I encounter when auditing cloud spend for startups. Always model costs before adoption.

ProviderFree Tier (Storage / Bandwidth)Paid Rate (per GB/month)Max Single FileSelf-Hostable
GitHub1 GB / 1 GB$0.07 storage + $0.09 bandwidth2 GB (standard), 5 GB (Enterprise)No
GitLab.com10 GB / 10 GB$0.065 storage + $0.09 bandwidth5 GBYes (S3/GCS backend)
Azure DevOpsUnlimited (fair use)Included up to org limit5 GBYes (Azure Blob)
Self-hosted (MinIO/S3)Hardware cost only$0.023 (S3 Standard equiv.)UnlimitedYes

For Nepal-based teams managing sensitive data or operating under strict budget constraints, self-hosting LFS against MinIO or a local S3-compatible gateway often makes more sense than paying recurring SaaS fees. Pair this with cloud cost optimization tactics to keep storage expenses predictable.

SaaS LFS (GitHub/GitLab)AuthAPICDNManaged • Per-GB billing • Zero opsSelf-Hosted (MinIO/S3)IAMGatewayDisksFull control • Fixed cost • Ops requiredDecision CriteriaCompliance • Budget • Team size • Data residencyChoose architecture based on Git LFS for large files requirements
SaaS versus self-hosted Git LFS for large files storage comparison for compliance and cost planning

When should you avoid Git LFS entirely?

LFS is not a universal solution. In my experience supporting infrastructure across AWS, Azure, and on-prem environments, these scenarios demand alternatives:

  • Files changing every commit: LFS stores full copies per version, not deltas. A 500MB dataset updated daily creates massive storage bloat. Use DVC, LakeFS, or direct S3 versioning instead.
  • Public open-source projects: Most free-tier LFS quotas are insufficient for popular repos. Host releases on GitHub Releases, SourceForge, or Cloudflare R2 with signed URLs.
  • Build artifacts: Compiled binaries belong in artifact repositories (Nexus, Artifactory, ECR), not source control. See container registry guides for proper separation.
  • Sub-second access latency required: LFS adds HTTP round-trips during checkout. If your CI pipeline checks out thousands of small LFS files, consider vendoring or submodule strategies.

Performance pitfalls to watch

Even when LFS is appropriate, misconfiguration causes pain. The lfs.fetchexclude and lfs.fetchinclude configs are essential for monorepos where developers only need subsets of tracked assets. Without them, every clone pulls terabytes unnecessarily. Also enable lfs.concurrenttransfers (default 3) to match your network capacity; raising it to 8–12 significantly improves throughput on high-bandwidth connections common in Kathmandu's newer fiber deployments.

How do you troubleshoot common Git LFS failures?

Most LFS issues stem from hook misalignment or authentication expiry. Start diagnostics here:

  1. Pointers downloaded instead of files: Run git lfs pull. If it fails, check git lfs env for endpoint mismatches. Verify .gitattributes was committed before the affected files.
  2. Push rejected with "batch response": Usually auth or quota. Test with GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push to inspect HTTP responses. Rotate tokens if using PATs; SSH-based LFS auth is more reliable long-term.
  3. Smudge filter errors on checkout: Corrupt cache. Clear with git lfs prune then git lfs fetch --all. Check disk space; LFS cache defaults to ~/.local/share/lfs and can exhaust small VPS volumes.
  4. CI timeouts: Add GIT_LFS_SKIP_SMUDGE=1 to skip downloading during shallow clones, then fetch only needed paths explicitly. This alone has rescued dozens of failing pipelines I've audited.
LFS Failure DetectedRun: git lfs env + GIT_TRACE=1Auth / Endpoint ErrorRotate token • Check URLPointer / Smudge Errorgit lfs pull • Prune cacheQuota / TimeoutSkip smudge • Fetch partialVerify: git lfs ls-files + Fresh CloneSystematic resolution for Git LFS for large files issues
Diagnostic flowchart for resolving Git LFS for large files failures in development and CI

Implementing Git LFS for Large Files With Confidence

Adopting Git LFS for large files is straightforward mechanically but demands thoughtful governance around cost, migration risk, and team workflows. Start with clear tracking policies, validate migrations on isolated clones, monitor storage spend monthly, and maintain runbooks for the inevitable auth or cache issues. When implemented with this level of rigor, LFS preserves Git's collaborative strengths without sacrificing performance at scale.

If your team needs help designing LFS architecture, migrating legacy repositories safely, or integrating LFS with compliant cloud storage backends, reach out to discuss your infrastructure requirements. I regularly assist organizations across Nepal and globally with version control strategies that balance developer velocity with operational sustainability.

Frequently Asked Questions

Git LFS replaces large binary files with text pointers in your repository while storing actual content on a remote server, keeping clones fast and history clean.

Run git lfs install after installing the package via brew, apt, or choco. This sets up global hooks automatically for tracking and transferring large file assets.

Track binaries like videos, PSDs, ML models, and compiled assets exceeding 100MB. Avoid tracking source code or small configuration files that benefit from standard diffing.

Yes. Use actions/checkout@v4 with lfs: true to fetch pointer files and actual content during workflow runs, ensuring builds have access to required binary assets.

Most hosts offer free tiers with bandwidth limits. GitHub provides 1GB storage and 1GB monthly bandwidth gratis; exceeding this requires purchasing data packs or upgrading plans.

Use git lfs migrate import --include="*.bin" --everything to rewrite history. Force push afterward and coordinate with all contributors to reclone repositories to avoid corruption.

Clones remain slow if LFS objects are missing remotely or network throttling occurs. Verify server support, check bandwidth quotas, and ensure pointers resolve correctly via git lfs ls-files.

Yes. Enable object storage in gitlab.rb and configure S3-compatible backends. Ensure nginx proxy buffers accommodate large uploads and verify LFS settings in admin dashboard.

Pushes fail with HTTP 507 errors until storage or bandwidth resets. Monitor usage via host dashboards and purchase additional data packs or prune old LFS objects immediately.

LFS cannot merge binary content automatically. Conflicts require manual resolution by choosing one version entirely. Use descriptive filenames and lock files to prevent concurrent edits.

Encryption depends on your storage backend. Cloud providers encrypt by default; self-hosted setups require configuring TLS and server-side encryption for the underlying object storage layer.

Yes. Update .gitattributes, run git lfs untrack, then commit changes. Existing versions remain in LFS storage until garbage collected; new commits store files normally in Git.

Partial clones fetch only needed LFS objects on demand rather than downloading everything upfront. Enable via git clone --filter=blob:none to reduce initial checkout time significantly.

Consider DVC for ML datasets, artifact registries for build outputs, or cloud storage with signed URLs. These decouple version control from asset management better than LFS.

Set GIT_TRACE=1 and GIT_CURL_VERBOSE=1 to inspect HTTP requests. Check server logs for authentication failures, timeout configurations, and verify pointer file integrity matches remote hashes.