Skip to main content
ertius.org

git-lfs is a weird one

I quite like using git for managing le content, but I also quite like not having a repository get megabytes bigger every time I add a screenshot, so I thought today would be a good day to try out git-lfs, which basically stores large files out of band and just versions the metadata and a reference to them.

First of all, I wanted a directory to just chuck things in - let's call it ./blobs. This requires a .gitattributes file in the repository root that looks like this:

blobs/** filter=lfs diff=lfs merge=lfs -text

As I often do with git, since it doesn't have any interest in committing an empty directory, I added a README.md file to the directory. No amount of fucking around would make git-lfs not try to add the README.md as an LFS file (and it's not just me).

[attr]not-lfs !filter !diff !merge text

blobs/** filter=lfs diff=lfs merge=lfs -text
blobs/README.md not-lfs

not

blobs/** filter=lfs diff=lfs merge=lfs -text
blobs/README.md -filter -diff -merge -text

Eventually I gave up and just added blobs/README.md first, then added the .gitattributes file after, and that seems to work.

While it didn't seem to stop screwing around with the file to begin with, adding this to .gitattributes does seem to mostly work, and removing it manages to trigger this issue in magit:

blobs/README.md -filter -diff -merge -text

So, I'm not really sure. Perhaps I'm just misunderstanding how it's meant to work.

Anyway, I had my README.md as a text file and added a couple of binary files. Now for the easiest part, time to push the repository! Let's do that:

Pushing to ssh://my.forgejo.example/user/repo.git
Uploading LFS objects:  50% (1/2), 173 KB | 3.3 KB/s, done.
LFS: Client error &{%!!(string=https) %!!(string=) %!!(*url.Userinfo=<nil>) %!!(string=my.forgejo.example) %!!(string=/user/repo.git/info/lfs/objects/3287493847ab1231231235452431221/412341234) %!!(string=) %!!(bool=false) %!!(bool=false) %!!(string=) %!!(string=) %!!(string=)}s(MISSING) from HTTP 413

Well, that's unexpected. Especially unexpected is getting an HTTP error from a ssh push. I had been fucking around a lot with LFS by this point so spent a while looking at paths and permissions on the server to see if I'd collided something, but then I searched a lot for "HTTP 413 git-lfs" and got annoyed at all the results just being people misconfiguring the max body size limit for their frontend HTTP proxy rather than explaining my special SSH problem. Eventually it occurred to me that having an HTTP error might actually indicated an HTTP problem, so I read one of the nginx articles and it was about files above 5MB causing problems, and noticed that precisely one out of two files copied OK, then I had a look at ./blobs directory:

 ls -l blobs/
-rw-r--r-- 1 rob staff     130 May  3 14:19 some-small-file
-rw-r--r-- 1 rob staff     114 May  3 14:00 README.md
-rw-r--r-- 1 rob staff 5103114 May  3 14:19 some-file-above-5MB

anyway, I added client_max_body_size 3000m; to the proxy config in nginx and then it worked, voila.

Eventually I found the rather surprising fact that git-lfs historically only used ssh for authentication, doing the actual data transfer via HTTP. There's a proposal to not do that and an out-of-tree implementation.

gitea actually has a config option to do it all over ssh, which is disabled by default due to a now-fixed bug in git-lfs (and another one). forgejo hasn't ported that code yet since it has bad test coverage, which is a bit unfortunate.

Anyway! Now it mostly works.