Open-source project
getgat-dev/gat avatar
getgat-dev/gat

gat stores large files in object storage and leaves git alone

Simple, fast, versioned large-file storage for git 🚀 https://getgat.dev

695 stars34 forksRustApache-2.0

At a glance

What is it?
gat is a Rust command line tool that keeps large files in an object store while git tracks a small lock file, with no clean and smudge filters and no LFS-style server to run. It positions itself as what git-lfs would be without the special server, and what dvc would be if it did one thing.
Who is it for?
gat suits a team that wants model weights, datasets or build artefacts versioned alongside code, that already runs object storage, and that has been put off git-lfs by the server and protocol overhead. It is the wrong tool if your collaborators are on tooling that only speaks the Git LFS protocol, or if you have no object store to point it at.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What gat claims to be instead of git-lfs

The README positions gat with one sentence that contains the whole argument. It is what git-lfs would be if it didn't need a special server, and what dvc would be if it did one thing.

Both halves of that comparison are about removing a moving part. Git LFS needs a server that speaks the LFS protocol, stores objects and hands back pointers, and a client with clean and smudge filters that intercept every Git operation. dvc is a data versioning system that does much more than one thing. gat keeps the storage job and drops the rest: point it at S3, Azure Blob, GCS, and other object stores, or a plain directory, add your large files or directories, and keep using git exactly as before, with commit, push, pull and clone all just working.

The mechanism that makes that possible is the absence of filters. There is no clean/smudge filter magic, and instead gat sync automatically reconciles the working tree with the current gat.lock.

So the model is a lock file in Git plus the payload in a bucket. Git tracks what is true about the large files, and the object store holds the bytes. Anything that clones the repository gets the lock, and then runs gat sync to write out the files.

The audience is teams with large binary artefacts, model weights being the example the quick start uses, who want them versioned with the code and who already have somewhere to put the bytes.

The lock file, the config file, and the sync

Two files appear in the quick example, and it is worth being clear about which is which.

gat.lock is the tracked artefact. It is the record that Git commits, and it is what gat sync reconciles the working tree against. gat.yaml is the configuration, which the example also stages with git add, which tells you the storage configuration is meant to travel with the repository rather than live in one developer's home directory.

The sync model has a consequence that is easy to miss. Because the working tree is reconciled by a command rather than intercepted by filters, a fresh clone is not immediately complete. You have gat.lock and the code, but not the payload, and gat sync is what fills it in. The README is careful about this and points at the How Gat works documentation for the lock, the cache and the working files.

The second thing worth understanding is that adding a remote does not select a default. You have to pass --remote origin for each transfer, or run gat remote default origin once to make the choice stick. The README links a remote setup page for sharing storage configuration across a team, which is the part that matters when several people work on the same repository.

This is the trade the project is making. You give up the transparency of filters, where a clone appears to bring everything with it, and you gain a storage backend that is an ordinary bucket with ordinary credentials.

Installing the binary, and the Rust floor underneath it

Installation is a script on both major platforms, and the Linux and macOS one is a single line:

bash
curl -fsSL https://getgat.dev/install.sh | sh

On Windows, in PowerShell, it is the equivalent:

powershell
& ([scriptblock]::Create((irm https://getgat.dev/install.ps1)))

Both do the same three things, according to the README. They download the latest matching release archive, verify its checksum, and install gat to your user-local bin directory. The checksum verification is the part that matters for a pipe-to-shell install, because it means the script is not asking you to trust the bytes it just downloaded.

The installation documentation also covers version-pinned installs, manual downloads, and Cargo-based source installs. The last one is a single command:

bash
cargo install --locked --bin gat --git https://github.com/getgat-dev/gat gat

The --locked flag matters for a git install, because it pins the dependency versions in the lock file rather than resolving them fresh.

The toolchain requirement is worth noting because the project treats it as a contract. Building gat from source requires Rust 1.91 or newer, the minimum supported Rust version tracked by rust-version in Cargo.toml, and the README states that bumping the MSRV is considered a breaking change. The manifest confirms it, with edition 2024, rust-version 1.91 and version 0.0.15.

A first repository, end to end

The quick example is a real sequence inside an existing Git repository, using a file Git does not already track. You replace the bucket and region and configure storage credentials.

sh
gat init
gat remote add origin 's3://my-bucket/assets?region=eu-west-1'
gat add models/encoder.safetensors
git add gat.lock gat.yaml
git commit -m "Track encoder weights with gat"
gat push --remote origin

Each step has a distinct owner, and the distinction is the point of the design. gat init creates the project state, gat remote add registers where the payload lives, and gat add records the file in gat.lock. The next three lines are ordinary Git: stage the lock and the config, commit with a message, and nothing else. gat push --remote origin is the only command that moves bytes, and it needs the explicit --remote because adding a remote does not select a default.

The file being tracked is a model weight file, models/encoder.safetensors, which is a fair illustration of the workload. These are the files that make a Git repository unpleasant to clone, and the ones people end up with a .gitignore for and a download script in the README.

The documentation list in the README names the pages to read next: a quickstart for tracking, pushing and pulling a first file, the installation page, a page on setting up a remote, a page for the Gat MCP server, which connects an AI tool to the documentation, and a commands reference with one page per subcommand.

A workspace with a crate for each concern

The Cargo.toml describes a workspace with an explicit membership list, and the split tells you what the project considers separable.

The members are test-support-git, test-support-gat, gat-core, gat-io, gat-engine, gat-command, and three developer tools, tools/docs, tools/benchmark and tools/check. The default members are the root package, the two test support crates and the three product crates, with a comment explaining that the developer generators are workspace members so locked workspace checks cover them, but they are omitted from default members so ordinary builds compile only the product and its test-support crates.

That is a careful arrangement, and it says the project is serious about build time as well as correctness. Two dedicated test-support crates, one per side of the boundary, suggests the tests exercise the real Git and the real gat rather than mocks, though the repository also carries a mock/ directory of its own.

The dependencies are a short, modern list: clap with derive and wrap_help for the command line, tokio for the async runtime, rayon for parallelism, indicatif for progress bars, anstream and anstyle for terminal output handling, terminal_size and unicode-width and unicode-segmentation for layout, and thiserror for error types. Two comments in the dependency list explain ownership boundaries: yaml_serde serializes typed config-list outcomes at the root machine-output boundary while physical gat.yaml persistence remains owned separately by gat-io.

The rest of the repository follows the same pattern. There are src/ with the library and the binary entry points, benches/ with a benchmark target whose harness is set to false, a Taskfile.yml for task running, and AGENTS.md, CONTRIBUTING.md and SECURITY.md for the human and automation sides of the project.

Where gat is the wrong tool

Three cases, and the first one is a compatibility question you should answer before anything else.

If your collaborators, or your CI, or any tool in your pipeline expects the Git LFS protocol, gat will not satisfy it. The README is explicit that gat works this way because git-lfs would not need a special server, which means the pointer format and the client behaviour are gat's own. A team with a mixed toolchain, where one person uses an editor with built-in LFS support, has a problem that gat does not solve.

The second is the storage requirement. gat wants an object store, and it wants credentials, and the credentials for S3, Azure Blob or GCS are not the same as the credentials for a Git remote. The quick example puts the region in the remote URL and points at a separate credentials mechanism, which means the team is now running two sets of secrets. For a single developer on a laptop that is fine. For a company with a policy about where credentials live, it is a conversation.

The third is the maturity of the artefact. The version in the manifest is 0.0.15, and the recent tags are v0.0.14 from 2026-09-26, v0.0.13 from 2026-09-18 and v0.0.12 from 2026-09-16, so three releases landed in ten days in September 2026. That is a fast pace and a young version line at the same time, and it means the lock file format and the command surface may still move.

The README also does not document how old object versions are reclaimed when a file is replaced, so anyone planning to use it for a directory of large artefacts should ask that question before migrating a repository onto it.

Licence, releases and the shape of the project

The licence is Apache-2.0, declared in the manifest and with a LICENSE file at the repository root, so the code can be used, modified and redistributed with attribution and with a patent grant.

The release history is the one place the pace is clear. Three tags in September 2026, v0.0.12 on the 16th, v0.0.13 on the 18th and v0.0.14 on the 26th, and a manifest version of 0.0.15 on top of that, with the last push on 2026-10-19 and the repository not archived. So the code is being worked on and the numbers are moving, but the line is pre-1.0, which is the usual signal that interfaces and file formats may still change.

The project pages point at getgat.dev, with a separate installation page for version-pinned and manual installs, a remote setup page, a concepts page on how gat works, and a commands reference with one page per subcommand. There is also a guide for the Gat MCP server, described as a way to connect your AI tool to the docs, which is an interesting choice for a project whose own documentation is the thing a tool needs to understand.

The homepage is not listed in the repository metadata, but the manifest gives https://getgat.dev as the homepage and the README links it as the documentation entry point.

For an evaluation, the shortest path is the installation script and the quick example, because the whole workflow is three gat commands and three git commands. If the object store layout and the lock file survive a first trial on a scratch repository, the project is doing what it claims. If they do not, the filters and the protocol of Git LFS are the alternative, and gat has told you plainly that it is not trying to be that.

Editorial conclusion

gat suits a team that wants model weights, datasets or build artefacts versioned alongside code, that already runs object storage, and that has been put off git-lfs by the server and protocol overhead. It is the wrong tool if your collaborators are on tooling that only speaks the Git LFS protocol, or if you have no object store to point it at. Verify first that the object layout gat writes is compatible with how your team consumes those files, that the remote URL form your provider uses is one gat accepts, and that the lock file format your CI checks in is the one gat produces, since the project is still on a 0.0.x version line with releases that have moved three times in September 2026.

Frequently asked questions

How do I install gat?

Run curl -fsSL https://getgat.dev/install.sh | sh on Linux or macOS, or the PowerShell equivalent on Windows. The script downloads the latest matching release archive, verifies its checksum and installs gat to your user-local bin directory, and Cargo-based source installs are also documented.

How does gat differ from git-lfs?

The README describes gat as what git-lfs would be if it did not need a special server. gat keeps the payload in an object store such as S3, Azure Blob or GCS and tracks a lock file in git, and it avoids clean and smudge filter magic by reconciling the working tree with a gat sync command.

What do I commit to git when I use gat?

The quick example stages gat.lock and gat.yaml with git add before committing. The lock is the tracked record of the large files, and the configuration file holds the storage setup so it travels with the repository.

Does adding a remote in gat make it the default?

No. Adding a remote does not select a default, so you use --remote origin for each transfer or run gat remote default origin to set it once. The remote setup documentation covers sharing storage configuration with the rest of the team.

Official sources

  1. getgat-dev/gat on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/getgat-dev-gat.svg)](https://hysenlabs.com/projects/getgat-dev-gat)

Was this useful?