/til/

2025 1213 git-lfs-transfer

While “the future of large files in git is git”, the present of large files in git is still something like git-lfs.

One of git’s selling points to me is its distributed nature, and the ease of setting up a simple server with sshd. I am happy to pay GitHub to handle hosting and CI because I’m not locked in there — I can and have switched repos away to personal hosting and other forges and then back again to GitHub. But git-lfs breaks this: one you have files tracked in LFS, you can only push to other git servers that provide LFS, which for self-hosting means something more complicated than a simple SSH server.

Or so I thought, until I discovered git-lfs-transfer, which can be installed on the server to provide git LFS hosting over ssh. This program has two implementations I’m aware of:

I found these today when I needed to work with an LFS-enabled repository in my Claude Code prison. This VM happened to have Go tooling already installed, so I used the charmbracelet port.

I ran this on the server:

sudo dnf install git-lfs
go install github.com/charmbracelet/git-lfs-transfer@latest
sudo cp ~/Documents/Go/bin/git-lfs-transfer /usr/local/bin/
sudo chmod 755 /usr/local/bin/git-lfs-transfer

Then on the client I could:

# Using ssh:// URLs may be a requirement, see below
git remote add REMOTE ssh://USER@HOST/path/to/repo.git
# Yes, the https:// is reequired for this, probably a holdover from previous HTTP-only LFS implementation
git config lfs.https://HOST/path/to/repo.git/info/lfs.locksverify false

After that, pushing my LFS-enabled git checkout to my server worked perfectly from the client. No HTTP required!

Troubleshooting & references

  • This requires git-lfs 3.0 or newer
  • Git over ssh does not execute your shell before running commands, so any $PATH configuration that includes Go or Rust bin directories doesn’t get applied. For me this just included /usr/bin and /usr/local/bin. See it with ssh USER@HOST 'echo $PATH'.
  • If you see an error message related to a missing git-lfs-authenticate binary, that means that using git-lfs-transfer has failed for some reason. git-lfs-authenticate is the normal way that forges enable pulling large files from their HTTP servers, and because it’s forge-specific, there is no generic implementation shipped with git-lfs. If git-lfs-transfer fails (or is not in the $PATH, or your git-lfs version is too old, etc), it will fall back to git-lfs-authenticate. (Some details in this comment.)
  • It may be necessary to use ssh://USER@HOST/path/to/repo.git remote URIs rather than USER@HOST:/path/to/repo.git style.
  • As far as I know, the two git-lfs-transfer implementations don’t have a way to support LFS locks. LFS locks are an optional coordination feature for preventing simultaneous edits of the same file. If you don’t explicitly disable it as shown above, git will warn you on every push that it isn’t supported.
  • git-lfs has a little hack for pushing to repos on the local filesystem, so git push /path/to/wherever.git should work just fine even if your working copy is LFS-enabled

Responses

Webmentions

Hosted on remote sites, and collected here via Webmention.io (thanks!).

Comments

Comments are hosted on this site and powered by Remark42 (thanks!).