Managing Large Files with Git LFS

Earn 25 points (50 with Pro) in two steps

  1. ① Read through the lesson — each section gets a ✓ as you scroll through it.
  2. ② When every section has a ✓, tap Complete lesson.

0 of 8 read · keep scrolling

✦ See fewer ads and earn double points — 50 a lesson instead of 25 — with Pro

Managing Large Files with Git LFS: A Comprehensive Guide

Introduction: The Git Repository Problem

Git was originally designed to manage source code—text files that are relatively small, highly compressible, and line-based. Because Git tracks the history of every file by creating snapshots of its entire state, it excels at diffing text and merging changes. However, when you introduce large binary files into a Git repository, the performance of the system begins to degrade rapidly. If you store a 500MB high-resolution texture or a compiled binary library in a standard Git repository, every time you commit a change to that file, Git stores a new, full-sized copy of it in your .git directory. Over time, this leads to massive repository sizes that make cloning, pulling, and pushing operations painfully slow for every member of your team.

This is where Git Large File Storage (LFS) comes into play. Git LFS is an open-source extension for Git that replaces large files with tiny text pointers inside the repository. The actual file content is stored on a remote server, such as a specialized LFS server or a cloud storage provider, and only downloaded when you specifically check out the branch or pull the files. By offloading these heavy assets, Git LFS allows your repository to remain lightweight and fast, regardless of the size of the assets you are tracking. In this lesson, we will explore why this is essential for modern development, how to implement it, and how to maintain a healthy repository workflow.


Not read yet

Why Git LFS Matters

In modern software development, particularly in game development, data science, and machine learning, repositories are rarely limited to just source code. Developers frequently need to manage assets like 3D models, audio files, video clips, datasets, and container images. If these files were tracked directly by Git, the repository would quickly reach a size that makes it impossible to clone on standard internet connections.

Furthermore, Git is not optimized for binary file merging. When two people modify a text file simultaneously, Git can often help merge the changes automatically. When two people modify a 500MB binary file, Git cannot merge them; it must choose one version over the other, leading to data loss. Git LFS addresses these performance and storage issues by decoupling the file storage from the version control metadata. This keeps the .git folder slim and ensures that operations like git fetch remain performant.

Callout: The Pointer File Concept Git LFS works by replacing your large files with a small text file called a "pointer." This pointer contains a unique identifier (a SHA-256 hash) of the file, the file's size, and a reference to where the actual content lives on the remote server. When you run a command like git checkout, Git LFS intercepts the process, checks the pointer, downloads the actual file from the remote storage, and places it in your working directory. This ensures you only ever download the large files you actually need for your current work.


Not read yet

Setting Up Git LFS

Implementing Git LFS is a straightforward process, but it requires coordination across your team. Everyone who interacts with the repository must have the Git LFS client installed on their local machine.

Step 1: Installing the Client

First, verify if you have Git LFS installed by running the following command in your terminal:

git lfs --version

If the command returns a version number, you are ready to go. If not, you will need to install it. On macOS, you can use Homebrew with brew install git-lfs. On Windows, the Git for Windows installer typically includes an option to enable LFS. On Linux systems, you can use your distribution's package manager, such as sudo apt-get install git-lfs.

Step 2: Initializing LFS for a Repository

Once installed, you must initialize Git LFS for each repository where you want to use it. This creates the necessary configuration files and hooks within your local project.

cd /path/to/your/repository
git lfs install

The git lfs install command sets up the necessary Git hooks that allow Git to communicate with the LFS client during operations like commit, checkout, and push.

Step 3: Tracking Large Files

You do not want to track every file with LFS, as this would be inefficient for standard source code. Instead, you specify which file types or specific files should be handled by LFS using the git lfs track command. This creates or updates a file named .gitattributes in your repository root.

# Track all .psd files
git lfs track "*.psd"

# Track all .mp4 files
git lfs track "*.mp4"

# Track a specific large file
git lfs track "assets/data/large_dataset.csv"

After running these commands, you will see a .gitattributes file. It is critical that you commit this file to your repository, otherwise, your teammates will not know which files are configured for LFS.

git add .gitattributes
git commit -m "Configure Git LFS for image and video assets"

Not read yet

Managing the Workflow

Once LFS is configured, the day-to-day workflow feels remarkably similar to standard Git usage. You add files, commit them, and push them to the remote server. However, there are nuances to how the data is transferred that you should understand.

Adding and Committing

When you add a file that matches your LFS patterns, Git LFS automatically intercepts the git add command. Instead of adding the binary file to the Git index, it creates the pointer file and stores the binary locally in a hidden .git/lfs directory.

# Add a large file
git add assets/textures/main_character.png

# Commit as usual
git commit -m "Add main character texture"

Pushing Changes

When you run git push, the Git LFS client scans your commits to identify the binary files associated with the pointers. It then uploads the actual binary data to the LFS storage server before the Git push completes. If the LFS upload fails, the Git push will also fail, ensuring that your remote repository never contains broken pointers that point to missing data.

Pulling and Cloning

When a teammate clones the repository, they will initially only download the pointer files. This makes the initial git clone extremely fast. To download the actual large assets, they must run:

git lfs pull

Alternatively, git checkout commands will automatically trigger the download of the necessary LFS files for the branch you are switching to. This "lazy loading" behavior is the core performance advantage of Git LFS.

Note: The "git lfs pull" vs "git pull" Distinction In older versions of Git LFS, you had to manually run git lfs pull after a git pull. Modern versions of Git LFS are much better at automatically fetching the necessary files during checkout. However, if you find that your files are missing or appear as text pointers in your file explorer, running git lfs pull is the standard way to synchronize your local working directory with the remote storage.


Not read yet

Best Practices and Industry Standards

To maintain a performant and organized repository, following standard practices is essential. Git LFS is a powerful tool, but misuse can lead to messy history and unexpected storage costs.

1. Track Binary Files Only

The most common mistake is tracking too many file types with LFS. Only track files that are truly large or binary in nature. Never track source code files like .js, .py, .cpp, or .html with LFS. These files benefit from Git's delta-compression and branching capabilities, which are lost if you move them into LFS.

2. Manage Your LFS Quota

Many hosting providers (like GitHub or GitLab) impose storage and bandwidth limits on Git LFS. If you are working on a project with massive assets, monitor your usage. Frequently committing large files that change often will consume your storage quota rapidly. If you have files that change daily and are very large, consider using a separate asset pipeline or an external storage bucket (like AWS S3) for those specific files, rather than Git LFS.

3. Use .gitattributes Consistently

Ensure that your .gitattributes file is maintained and consistent across all branches. If a new developer joins the team and pulls a branch where .gitattributes was not updated, they may inadvertently commit large files to the standard Git history, which is difficult to clean up later.

4. Optimize Large Repository Clones

If you have a massive project with thousands of LFS files, cloning the entire history can still be slow. You can use the --include flag to fetch only specific files or folders, though this is an advanced technique. For most teams, the standard git lfs pull is sufficient.

Warning: Removing Files from LFS Removing a file from LFS tracking is difficult because the file has already been committed to the history. If you decide to stop tracking a file type, you must update the .gitattributes file, but the old versions will remain in the LFS storage. To truly remove large files from your history, you would need to use tools like git-filter-repo to rewrite the entire commit history of the repository, which is a destructive process that requires all team members to re-clone the repository.


Not read yet

Comparison of Git Tracking vs. Git LFS

Feature Standard Git Git LFS
Storage Location Inside .git directory Remote LFS server
Download Speed Downloads everything Downloads only required files
Diffing Ability Full support for text files No support for binary files
Repository Size Grows with every binary commit Remains small (pointer files)
Performance Degrades as repo grows Stable performance

Common Pitfalls and Troubleshooting

Even with a well-configured setup, developers occasionally run into issues. Here are the most common scenarios and how to resolve them.

Missing LFS Objects

If you receive an error stating that an LFS object is missing, it usually means the file exists on the server, but your local client failed to fetch it. You can attempt to force a fetch of all objects for the current commit:

git lfs fetch --all
git lfs checkout

Large Files Committed to Git History by Mistake

If someone accidentally commits a large binary file without LFS, it is now part of the Git history. Simply adding the file to git lfs track afterward does not remove the file from the history. You must remove the file from the index and commit the change, but the file will persist in the .git database. To purge it, you must use a history-rewriting tool. The best approach is to prevent this via pre-commit hooks that check for file size before allowing a commit.

Server Connection Issues

If your push fails, verify your network connection and ensure your LFS server URL is configured correctly. You can check the current configuration with:

git config -l | grep lfs

If the URL is incorrect, you can update it using git config lfs.url <new-url>.


Not read yet

Step-by-Step: Migrating an Existing Repository to LFS

If you have an existing repository that has become bloated because you were tracking large files normally, you can migrate it to LFS. This process requires caution.

  1. Backup: Always create a full backup of the repository before performing a migration.
  2. Install BFG Repo-Cleaner: This tool is often faster and easier than git filter-branch for removing large files from history.
  3. Remove Large Files: Use BFG to remove the large files from your history.
    java -jar bfg.jar --strip-blobs-bigger-than 50M
    
  4. Configure LFS: After the history is cleaned, run git lfs install and git lfs track for the file types you just removed.
  5. Re-add Files: Add the files back into the repository. Because they are now tracked by LFS, they will be converted into pointer files.
  6. Force Push: Since you have rewritten history, you will need to perform a git push --force to update the remote repository. Note that this will affect everyone else on the team, who will need to re-clone the project.

Not read yet

Advanced Topic: File Locking

In many creative workflows, two people cannot work on the same binary file simultaneously. Unlike code, where you can merge, you cannot merge two different versions of a 3D model. Git LFS provides a "File Locking" feature to solve this.

By marking a file as "lockable," you ensure that only one person can edit it at a time. When a user wants to edit a file, they run:

git lfs lock path/to/file.psd

This sends a request to the server to lock the file. If someone else has already locked it, the server will reject the request. When the user is finished, they run:

git lfs unlock path/to/file.psd

This prevents the "lost update" problem where two developers spend hours working on the same asset only to have one person's changes overwritten by the other. This is an industry-standard practice for game studios and design agencies.


Summary and Key Takeaways

Managing large files in Git requires a disciplined approach to ensure your development environment remains fast and functional. Git LFS is the industry standard for handling this challenge, providing a clean separation between source code and heavy binary assets.

Here are the key takeaways from this lesson:

  • Understand the Pointer System: Git LFS works by replacing large files with text pointers, keeping your core Git repository lightweight and performant.
  • Selective Tracking: Only track large binary files with LFS. Keep your source code (text files) managed by standard Git to maintain the benefits of delta-compression and merging.
  • Initialization is Mandatory: Every developer on the team must run git lfs install to enable the necessary hooks. Failure to do so will result in files being committed as raw data rather than LFS pointers.
  • Use .gitattributes: This file is the source of truth for your LFS configuration. It must be version-controlled and shared across the entire team to ensure consistency.
  • Leverage File Locking: For assets that cannot be merged (like binary design files), use the Git LFS file locking feature to prevent concurrent modifications and lost work.
  • Monitor Quotas: Large files consume storage and bandwidth. Keep an eye on your hosting provider's limits to avoid unexpected service interruptions or additional costs.
  • Handle History Carefully: Migrating a mature, bloated repository to LFS is possible but requires rewriting history. Always communicate clearly with your team before performing such operations, as it will force everyone to re-clone the repository.

By implementing these strategies, you can scale your development projects to include massive assets without sacrificing the speed and reliability of your version control system. Proper repository management is not just about tools; it is about establishing a workflow that supports collaboration, prevents data loss, and keeps the development process moving smoothly.

Not read yet

Each section gets a ✓ as you scroll through it. Tap the button to jump to the next one.