You probably know that Git, unlike, say, SVN, does not store a full source copy of each version but rather only stores a copy of the very first version in the initial commit, and then just stores the differences (diffs) from there.

This means that by default, unless you tell git explicitly not to, when you clone a repository, you have the entire source’s history, but in a storage-efficient way. Which of course also means, that a clone is a full copy and thus backup of a git repository, and that you can push this repository to another git forge (e.g. GitHub and Forgejo) in parallel. This also means that you can work fully offline, as everything is just there.

Git LFS breaks this Git assumption. I use Git LFS for a repository of mine, which I usually host on GitHub, but today I wanted to upload a copy of my repo to my own Forgejo instance to have a backup.

It was during that upload, when I got an error about some Git LFS objects not being found, that I learned that Git LFS does not store a copy of all files by default, and thus, a Git clone is no longer a full backup nor fully workable offline. I guess it makes sense, when you use it – as the name suggests – for large files; you save storage on your machine and bandwidth on your forge. But of course you need to know that.

Luckily, my Git LFS is relatively small (currently 20 MiB of blobs and artefacts), which is still multiple times the size of the source code, though. So, to download a full copy, I ran:

git lfs fetch origin --all

Which downloaded all objects for me, which means I now have a full backup of all files and managed to upload it to my Forgejo instance. So, things are now in the state where my Git assumption expected it to be from the beginning.

There’s one more caveat I want to tell you about, though: Git LFS uses HTTPS, even when you cloned your repo with SSH and are using SSH for everything. This matters because if your web server does not accept large files, the upload will fail with HTTP 413 Content Too Large. This is especially important to note when you have Anubis in front of your Git forge; even if you configure your Git forge in Nginx to accept large files, you have to set that same config in Nginx for Anubis or else the upload will fail. Guess how I know.

Some off-topic Trivia at the End

Finally, and this is just a bit of trivia to give you on the way to avoid confusion: Git LFS objects are *not* tied to GitHub, even if it mentions GitHub in the objects. Let’s look at a Git LFS pointer:

version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345
(ending \n)

You see a GitHub URL, but that is just the URL of the *spec*, not of the location it is stored. The relevant parts are the hash, which are the hash of the file, and the size, which specifies the file size in bytes. I never looked at Git LFS pointers more closely until today, and errounously believed it points to where Git LFS objects are stored, but no! That’s good news, and one thing which does NOT break a Git assumption. ;)

That’s all!

I run this blog in my free time, consider donating a cup of coffee. :з