Published 2025-01-06.
Last modified 2025-01-18.
Time to read: 9 minutes.
git
collection.
I have published 7 articles about the Git large file system (LFS). They are meant to be read in order.
- Git Large File System Overview
- Git LFS Client Installation
- Git LFS Server URLs
- Git-ls-files and Wildmatch
- Git LFS Filename Patterns & Tracking
- Git LFS Client Configuration & Commands
- Working With Git LFS
- Evaluation Procedure For Git LFS Servers
- Git LFS server tests:
6 articles are still in process.
Instructions for typing along are given for Ubuntu and WSL/Ubuntu. If you have a Mac, most of this information should be helpful.
This Page Probably Contains Errors
This article is incomplete and may contain errors. It has been published to allow collaboration with fact-checkers. Not all of these scenarios might make sense to attempt to review. Do not rely on this information yet.
Null Servers
Of all the available Git LFS server choices, the option to do without a Git LFS server is the simplest to set up. In fact, you can do away with the Git server also and use a bare Git repository instead. You will lose the file locking feature, but few people use it.
A null Git LFS server could be set up for an individual or organization if a local area network is already set up and at least one machine is always available as a server. I have written this article with that assumption in mind.
For a null Git LFS server, all that is required is a network-accessible directory structure to store large files.
No client-side Git LFS filters or hooks are required
Use Cases
Doing without a Git LFS server has the following common use cases:
- File size overwhelms available bandwidth.
- Extremely sensitive documents, copies of which must not leave the building.
- Simplest possible Git LFS setup.
The following scenarios are complete examples of different ways of setting up null Git LFS servers.
- A locally accessible bare Git repository and a separate locally accessible directory for large files.
- A remote Git repository, such as GitHub, with a locally accessible directory for large files.
Restrictions & Requirements
- Only one concurrent user with write access.
- A computer is dedicated to acting as a server.
My Setup
I am the only person who has write access to my files.
I have an Ubuntu server in my apartment called
gojira
that is a media store, runs Plex,
and is a terrific programming environment.
This machine is normally never turned off.
It acts as a Samba server, runs an nginx web server, etc.
I used gojira
as a Git LFS server-side test platform.
Gojira
has a dedicated UPS and is mirrored to a backup machine called
bambam
.
I also have a laptop for working while traveling, and another laptop for performing on-location computer music. Both of these laptops need Git LFS, although the types of information stored on each are different.
I also have a desktop computer
(bear
)
that I wrote most of the website on.
Bear
needs to access everything that all the other machines have access to.
My user ID on all machines is mslinn
.
Bare Git Repositories
By convention, the name of the directory containing a bare Git repository ends with .git
.
However, this is not required.
Bare repositories do not have a working tree, so you cannot add files to them as you would for a normal repository. Instead, you must update a bare repository by pushing to it from a clone of the repository.
When to Use
It is possible to employ Git LFS with a bare Git repository, so long as the bare Git repository is accessible via a supported protocol. That means the bare Git repository must either be stored on the local machine, or on a local area network. Normally, one would store bare Git repositories on a local area network server.
The advantages of this scenario are:
- Security can be better than storing files in the cloud.
- This is the simplest way to use Git LFS; because only file servers are involved; the Git client does all the Git-related work.
Working with bare repositories is much simpler than the setup for all other configurations because no Git server and no Git LFS server are involved.
The git init ‑‑shared Option
The article entitled Shared Directories With POSIX Groups and SGID discusses POSIX groups and the SGID permission bit.
This section uses the git_access
POSIX group created in that article.
The most convenient way to allow others to push to a bare Git repository is to use the git init ‑‑shared
option.
This option causes the SGID bit to be set on the directory holding the Git repository.
The general format is:
$ git --bare --shared=some_value init
The --shared
option can have several values.
The possible values that are relevant to a locally accessible Git LFS from a bare repository are:
all
, everybody
, group
, true
, and world
.
When the ‑‑shared
option is specified,
the config variable core.sharedRepository
is set to 1 for group
sharing,
and is set to 2 for sharing with everybody
.
Otherwise, if the ‑‑shared
option is not specified, Git will use the permissions reported by
umask
.
See the man
page for git-init
for further details.
If you specify ‑‑shared=group
or ‑‑shared=true
,
the Set Group ID (SGID) permission for that directory will be set,
as shown in the highlighted s
permission bit in the code example below.
Note that test_repo.git
is created in the home directory of user mslinn
for this example.
mslinn@gojira ~ mkdir --mode=g+s test_repo.git
mslinn@gojira ~ sudo chgrp git_access test_repo.git
mslinn@gojira ~ ls -ld test_repo.git drwxrwsrwx 2 mslinngit_access
4096 Jan 20 13:51 test_repo.git/
mslinn@gojira ~ git init --bare --shared=group test_repo.git Initialized empty shared Git repository in /home/mslinn/test_repo.git
mslinn@gojira ~ ls -l test_repo.git total 28 -rw-rw-r-- 1 mslinn git_access 126 Jan 20 09:34 config -rw-rw-r-- 1 mslinn git_access 73 Jan 20 09:34 description -rw-rw-r-- 1 mslinn git_access 23 Jan 20 09:34 HEAD drwxrws
r-x 2 mslinn git_access 4096 Jan 20 09:34 hooks/ drwxrws
r-x 2 mslinn git_access 4096 Jan 20 09:34 info/ drwxrws
r-x 4 mslinn git_access 4096 Jan 20 09:34 objects/ drwxrws
r-x 4 mslinn git_access 4096 Jan 20 09:34 refs/
mslinn@gojira ~ cd test_repo.git
mslinn@gojira test_repo.git git config core.sharedRepository 1
Now lets clone the new repo from another computer, a Windows machine with WSL, which has had
/etc/fstab
augmented with the necessary incantation to mount my home directory on gojira
on the WSL file system.
See Mounting Shared Directories on WSL & Ubuntu for background on mounting shared drives on Ubuntu and WSL/Ubuntu. The remainder of this article assumes you have read the background article and it is fresh in your mind. Ubuntu on WSL is just a little bit different from native Ubuntu in how shared directories are mounted. The very small difference is quite important to get right.
mslinn@bear ~ sudo mount /mnt/gojira_mslinn
mslinn@bear ~ ls /mnt/gojira_mslinn/test_repo.git/ HEAD* config* description* hooks/ info/ objects/ refs/
mslinn@bear ~ git clone /mnt/gojira_mslinn/test_repo.git Cloning into 'test_repo'... warning: You appear to have cloned an empty repository. done.
You can open up the permissions such that anyone with access can update the repository.
This is the simplest configuration.
There are three equivalent ways of specifying this value:
‑‑shared=all
, ‑‑shared=world
and
‑‑shared=everybody
.
mslinn@gojira ~ mkdir --mode=g+s test_repo2.git
mslinn@gojira ~ sudo chgrp git_access test_repo2.git
mslinn@gojira ~ git init --bare --shared=everybody test_repo2.git Initialized empty shared Git repository in /home/mslinn/test_repo2.git
mslinn@gojira ~ cd test_repo2.git
mslinn@gojira test_repo.git git config core.sharedRepository 2
We can clone test_repo2.git
from the other computer as before.
The mount at /mnt/gojira_mslinn
is assumed to still be in place.
mslinn@bear ~ ls /mnt/gojira_mslinn/test_repo2.git HEAD* config* description* hooks/ info/ objects/ refs/
mslinn@bear ~ git clone /mnt/gojira_mslinn/test_repo2.git Cloning into 'test_repo2'... warning: You appear to have cloned an empty repository. done.
receive.denyCurrentBranch
You could set the receive.denyCurrentBranch
configuration variable
to ignore
or updateInstead
.
While this does nothing for a null Git LFS server, it eliminates a warning that is meaningless for this configuration.
We will see this in action later.
newBareRepo Creation Script
The following script creates a bare Git repository with --shared=all
:
#!/bin/bash function help { if [ "$1" ]; then echo "$1"; fi echo "$(basename "$0") - Create a new bare git repository. Syntax: $(basename "$0") /path/to/new/repo A new git repository will be created in /path/to/new/repo, which should not already exist. The parent directory (/path/to/new/) must already exist. The name of the repo must not contain spaces. After creation, a new environment variable will be created in /etc/environment. The name that you specified ('repo' in the above example) will be used for the name of a new environment variable, set to the path that you specified. " exit 1 } if [ -z "$1" ]; then help; fi export REPO_PATH="$(dirname "$1")" if [ "$REPO_PATH" == ~ ]; then REPO_PATH="$HOME"; fi export REPO_NAME="$( basename "$1" )" if [ ! -d "$REPO_PATH" ]; then help "Error: '$REPO_PATH' does not exist."; fi if [ -f "$REPO_PATH/$REPO_NAME" ]; then help "Error: '$PATH/$REPO_NAME' already exists."; fi echo "$REPO_NAME=$REPO_PATH/$REPO_NAME" | \ sudo tee -a /etc/environment > /dev/null git init --bare --shared=all "$REPO_PATH/$REPO_NAME" chmod 777 "$REPO_PATH/$REPO_NAME" # Modify this to suit your security needs cd "$REPO_PATH/$REPO_NAME" || exit 3 # git config receive.denyCurrentBranch ignore if [ "$( which tree )" ]; then echo "The new repository contains the following subdirectory tree" tree -d fi echo "All done! The bare repository was created in '$REPO_PATH/$REPO_NAME'."
After copying newBareRepo
script to a directory on the PATH
,
make the script executable.
mslinn@gojira ~ $ chmod a+x /usr/local/bin/newBareRepo
This is the help message:
mslinn@gojira ~ $ newBareRepo newBareRepo - Create a new bare git repository. Syntax: newBareRepo /path/to/new/repo A new git repository will be created in /path/to/new/repo, which should not already exist. The parent directory (/path/to/new/) must already exist. The name of the repo must not contain spaces. After creation, a new environment variable will be created in /etc/environment. The name that you specified ('repo' in the above example) will be used for the name of a new environment variable, set to the path that you specified.
Blow-By-Blow Explanation
The following commands make a bare repository in a new directory on gojira
called $REPO_PATH
.
The repository will be open to all users that can access the server.
You do not need to type all of this out; the next section
shows how to use the above script to accomplish the same objective.
In the following console session, an environment variable is created,
called REPO_PATH
that points to the directory
that will contain the bare git repository.
I placed the definition for REPO_PATH
in the
/etc/environment
directory so it is available to every shell, even cron
jobs.
I used the
sudo tee -a
command
to append to /etc/environment
,
which is owned by root
.
The contents of /etc/environment
are then incorporated into the console session with the source
command.
mslinn@bear ~ $ ssh gojira
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-35-generic x86_64)
mslinn@gojira ~ $ REPO_PATH=$HOME/bare_repo
mslinn@gojira ~ $ echo "REPO_PATH=$REPO_PATH" | \ sudo tee -a /etc/environment > /dev/null
mslinn@gojira ~ $ source /etc/environment
Now we can create the bare Git repository according to the information in the previous section.
mslinn@gojira ~ $ git init --bare --shared=all "$REPO_PATH" Initialized empty shared git repository in /home/mslinn/bare_repo/
mslinn@gojira ~ $ chmod 777 "$REPO_PATH" # Modify this to suit your security needs
Alright, the bare Git repository has been created. Let’s admire our handiwork:
mslinn@gojira bare_repo $ tree -d "$REPO_PATH" . ├── branches ├── hooks ├── info ├── objects │ ├── info │ └── pack └── refs ├── heads └── tags
Using newBareRepo
Instead of typing out the commands in the previous section, you can create a bare Git repository by using the newBareRepo
script:
mslinn@gojira ~ $ newBareRepo ~/bare_repo Initialized empty shared Git repository in /home/mslinn/bare_repo/ The new repository contains the following subdirectory tree . ├── branches ├── hooks ├── info ├── objects │ ├── info │ └── pack └── refs ├── heads └── tags
10 directories All done! The bare repository was created in '/home/mslinn/bare_repo'.
An empty bare repository will be needed for each test scenario. We will leave this bare repository untouched and make a copy in a new directory afresh for each test scenario.
Choosing a Protocol
For these scenarios, the Git remote.origin.url
can be set to any suitable protocol,
including a flavor of the local protocol and ssh
.
While you could theoretically use the http
or https
protocols,
it would be unusual for a webserver to be configured on a local server for this purpose;
however, this would work.
The Git protocol is unavailable in this scenario because there is no Git server.
SSH is the most flexible protocol and is well understood. I have had good results with Git LFS over SSH when SSH keys have been deployed throughout the network. Without SSH keys, an authentication mechanism would be required.
The local protocol can be expressed two ways.
In the following two examples, /path/to/bare/
is a locally accessible path on a user machine.
This path could originate from a locally mounted file system, as previously discussed.
mslinn@bear ~ $ sudo mount /mnt/gojira_mslinn
mslinn@bear ~ $ ls /mnt/gojira_mslinn/test_repo.git HEAD* config* description* hooks/ info/ objects/ refs/
file:///gojira_mslinn/path/to/bare/repo.git
Note the 3 slashes after file:
.
mslinn@bear ~ $ git clone file:///mnt/gojira_mslinn/test_repo.git test1 Cloning into 'test1'... warning: You appear to have cloned an empty repository.
/gojira_mslinn/path/to/bare/repo.git
mslinn@bear ~ $ git clone /mnt/gojira_mslinn/test_repo.git test2 Cloning into 'test2'... warning: You appear to have cloned an empty repository.
If you are unaware of the restrictions of Git’s local protocol implementation, or the differences between the various flavors of the local protocol, please read The File URI Schema And The Local Protocol. That same article also discusses UNC paths.
Cloning On the Same Machine
On gojira
, the file system containing the the bare repo is of course already mounted.
The Git repository can be cloned from another local directory like this:
mslinn@gojira tmp $ git clone file:///home/mslinn/bare_repo.git Cloning into 'bare_repo'... warning: You appear to have cloned an empty repository.
Also like this:
mslinn@gojira tmp $ git clone /home/mslinn/bare_repo.git Cloning into 'bare_repo'... warning: You appear to have cloned an empty repository.
Scenarios Considered
The following scenarios were considered for this evaluation.
Scenario | Git Server | Git LFS Protocol | Use Cases |
---|---|---|---|
1 | None (bare repo) | Local (file )
|
|
2 | None (bare repo) | SSH |
|
3 | GitHub | Local (file )
|
|
4 | GitHub | SSH |
|
5 | GitHub | http
|
|
Scenario 1: Locally Accessible Bare Git Repository
Scenario | Git Server | Git LFS Protocol | Use Cases |
---|---|---|---|
1 | None (bare repo) | Local (file )
|
|
I am still working on this scenario.
I think maybe the problem I encountered below is because the protocol used when committing to LFS must be the same as was used when cloning.
Or maybe I committed the large files to Git instead of LFS.
$ git clone file://gojira/home/mslinn/bare_repo1 /tmp/asdf Cloning into '/tmp/asdf'... remote: Enumerating objects: 14, done. remote: Counting objects: 100% (14/14), done. remote: Compressing objects: 100% (13/13), done. remote: Total 14 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (14/14), done. Downloading 200MB.zip (210 MB) Error downloading object: 200MB.zip (d14b731): Smudge error: Error downloading 200MB.zip (d14b73150642f30d2342e6620fa537ea273a58b8b751fc5af8f4aabe809f8fc4): error transferring "d14b73150642f30d2342e6620fa537ea273a58b8b751fc5af8f4aabe809f8fc4": [0] remote missing object d14b73150642f30d2342e6620fa537ea273a58b8b751fc5af8f4aabe809f8fc4 Errors logged to '/tmp/asdf/.git/lfs/logs/20250117T144743.02793146.log'. Use `git lfs logs last` to view the log. error: external filter 'git-lfs filter-process' failed fatal: 200MB.zip: smudge filter lfs failed warning: Clone succeeded, but checkout failed. You can inspect what was checked out with 'git status' and retry with 'git restore --source=HEAD :/'
$ cd /tmp/asdf/
$ git status On branch master Your branch is up to date with 'origin/master'. Changes to be committed: (use "git restore --staged..." to unstage) deleted: .gitattributes deleted: 200MB.zip deleted: BigBuckBunny_640x360.m4v deleted: big_buck_bunny_480p_h264.mov deleted: big_buck_bunny_480p_stereo.avi deleted: big_buck_bunny_480p_stereo.ogg deleted: big_buck_bunny_720p_h264.mov deleted: big_buck_bunny_720p_stereo.avi deleted: big_buck_bunny_720p_stereo.ogg deleted: enwik9.zip deleted: normal_file.txt deleted: rdf-files.tar.zip Untracked files: (use "git add ..." to include in what will be committed) .gitattributes normal_file.txt
Scenario 2: Remote Git Repository With Locally Accessible Large Files
Scenario | Git Server | Git LFS Protocol | Use Cases |
---|---|---|---|
2 | None (bare repo) | SSH |
|
There are several equivalent syntaxes for specifying a Git URL for SSH. They provide identical results. Use the one that pleases you most. I tend to use the shortest URL possible.
Clone The Bare Repository On a Client Machine
A copy of the empty bare repository was placed in $HOME/bare_repo1
on server gojira
.
The following uses
brace expansion
as a shorthand expression.
mslinn@gojira ~ cp -a bare_repo{,1}
Clones of bare Git repositories are normal Git repositories.
Back on my desktop computer called bear
, I performed the following on WSL/Ubuntu:
-
Cloned the bare repository
bare_repo1
on the server calledgojira
to a new directory on my desktop computerbear
, into a new directory under the$work
directory.Shellmslinn@bear ~ $ mkdir $work/git_lfs && cd $work/git_lfs
mslinn@bear ~ $ git clone gojira:bare_repo1 Cloning into 'bare_repo1'... warning: You appear to have cloned an empty repository.
mslinn@bear git_lfs $ cd bare_repo1 -
No hooks are required because there is no Git server and no Git LFS server in this scenario,
so there will be no callbacks.
I included the
git lfs install
command because of the copy/paste habit that so many people have. These instructions should work even if you use these instructions with a non-null Git LFS server, provided that a suitable URL is used.Shellmslinn@bear bare_repo1 $ git lfs install # No-op Updated Git hooks. Git LFS initialized.
Let's see what the local copy of the bare Git repository looks like at this point:
mslinn@bear bare_repo1 $ git config remote.origin.url gojira:bare_repo1
mslinn@bear bare_repo1 $ ls # No files at present
mslinn@bear bare_repo1 $ tree -ad . └── .git ├── branches ├── hooks ├── info ├── objects │ ├── info │ └── pack └── refs ├── heads └── tags
13 directories
Set Up Tracking
All large files need to be tracked.
The patterns you provide via the git lfs track
command specify the filename patterns to be tracked.
Because media filenames might be in UPPERCASE or lowercase,
the patterns for media files are specified in lowercase and UPPERCASE using the
wp
script.
It is best to set up Git LFS tracking before adding large files to the Git repository.
The large files downloaded by
git_lfs_test_data
will be copied into this Git repository in the next section.
mslinn@bear bare_repo1 $ git lfs track $(wp avi m4v mov ogg zip) Tracking "*.avi" Tracking "*.AVI" Tracking "**/*.avi" Tracking "**/*.AVI" Tracking "*.m4v" Tracking "*.M4V" Tracking "**/*.m4v" Tracking "**/*.M4V" Tracking "*.mov" Tracking "*.MOV" Tracking "**/*.mov" Tracking "**/*.MOV" Tracking "*.ogg" Tracking "*.OGG" Tracking "**/*.ogg" Tracking "**/*.OGG" Tracking "*.zip" Tracking "*.ZIP" Tracking "**/*.zip" Tracking "**/*.ZIP"
The git lfs track
command created .gitattributes
and stored the wildcard patterns into it.
*.ZIP filter=lfs diff=lfs merge=lfs -text **/*.zip filter=lfs diff=lfs merge=lfs -text *.MOV filter=lfs diff=lfs merge=lfs -text *.ogg filter=lfs diff=lfs merge=lfs -text **/*.ogg filter=lfs diff=lfs merge=lfs -text **/*.OGG filter=lfs diff=lfs merge=lfs -text *.avi filter=lfs diff=lfs merge=lfs -text *.mov filter=lfs diff=lfs merge=lfs -text **/*.mov filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text **/*.ZIP filter=lfs diff=lfs merge=lfs -text *.AVI filter=lfs diff=lfs merge=lfs -text **/*.AVI filter=lfs diff=lfs merge=lfs -text *.M4V filter=lfs diff=lfs merge=lfs -text **/*.m4v filter=lfs diff=lfs merge=lfs -text *.OGG filter=lfs diff=lfs merge=lfs -text **/*.avi filter=lfs diff=lfs merge=lfs -text *.m4v filter=lfs diff=lfs merge=lfs -text **/*.M4V filter=lfs diff=lfs merge=lfs -text **/*.MOV filter=lfs diff=lfs merge=lfs -text
The git lfs track
command also created the .git/lfs
directory.
mslinn@bear bare_repo1 $ tree -ad . └── .git ├── branches ├── hooks ├── info ├── lfs │ └── tmp ├── objects │ ├── info │ └── pack └── refs ├── heads └── tags
13 directories
Add Content
It is time to add content to the Git repository:
- Create a normal file.
-
Copy the large files from the
git_lfs_test_data
script into the local copy of thebare_repo1
Git repository.
mslinn@bear bare_repo1 $ echo 'Hello world' > normal_file.txt
mslinn@bear bare_repo1 $ time scp gojira:git_lfs_test_data/* . 200MB.zip 100% 200MB 114.2MB/s 00:01 BigBuckBunny_640x360.m4v 100% 116MB 111.5MB/s 00:01 big_buck_bunny_480p_h264.mov 100% 102MB 111.4MB/s 00:00 big_buck_bunny_480p_stereo.avi 100% 149MB 113.2MB/s 00:01 big_buck_bunny_480p_stereo.ogg 100% 159MB 118.9MB/s 00:01 big_buck_bunny_720p_h264.mov 100% 397MB 115.0MB/s 00:03 big_buck_bunny_720p_stereo.avi 100% 271MB 111.8MB/s 00:02 big_buck_bunny_720p_stereo.ogg 100% 188MB 113.9MB/s 00:01 enwik9.zip 100% 308MB 115.1MB/s 00:02 rdf-files.tar.zip 100% 153MB 114.9MB/s 00:01 real 0m18.208s user 0m2.456s sys 0m2.433s
I previously mentioned that the
git add
command is slow when working with large files.
However, when large files are added to Git LFS,
the process only takes as long as necessary to place a copy of the large files in .git/lfs/objects
.
mslinn@bear bare_repo1 $ time git add -A real 0m11.237s user 0m3.315s sys 0m2.793s
As we know, gitadd
takes snapshots of normal files and saves them in the staging area
(.git/index
).
This repository only has one normal file (normal_file.txt
), so the Git index
is small right now:
$ du -h .git/index 4.0K .git/index
The large tracked files that were just added should have been snapshotted and saved to .git/lfs/objects
.
The last line of the following output is highlighted,
and shows that the total amount of data staged is 2 GB,
which, as you may recall, is the total amount of bunny videos that were downloaded.
mslinn@bear bare_repo1 $ du -h .git/lfs/objects 398M .git/lfs/objects/45/c8 398M .git/lfs/objects/45 150M .git/lfs/objects/4f/c7 150M .git/lfs/objects/4f 116M .git/lfs/objects/73/8e 116M .git/lfs/objects/73 188M .git/lfs/objects/78/5b 188M .git/lfs/objects/78 272M .git/lfs/objects/91/9e 272M .git/lfs/objects/91 102M .git/lfs/objects/98/95 102M .git/lfs/objects/98 308M .git/lfs/objects/99/cd 308M .git/lfs/objects/99 160M .git/lfs/objects/9b/98 160M .git/lfs/objects/9b 154M .git/lfs/objects/c5/60 154M .git/lfs/objects/c5 200M .git/lfs/objects/d1/4b 200M .git/lfs/objects/d1 2.0G .git/lfs/objects
We can even view the videos stored in the Git LFS staging area!
mslinn@bear bare_repo1 $ vlc .git/lfs/objects/45/c8/45c8bafeb9a53df7f491198d2e71529701bcf1cd51805782089fac1d32869f9b
Commit
Now the files need to be committed; this command executes quickly.
mslinn@bear bare_repo1 $ time git commit -m 'Added a normal file and large files' [master (root-commit) 7d0fe8c] Added a normal file and large files 12 files changed, 51 insertions(+) create mode 100644 .gitattributes create mode 100644 200MB.zip create mode 100644 BigBuckBunny_640x360.m4v create mode 100644 big_buck_bunny_480p_h264.mov create mode 100644 big_buck_bunny_480p_stereo.avi create mode 100644 big_buck_bunny_480p_stereo.ogg create mode 100644 big_buck_bunny_720p_h264.mov create mode 100644 big_buck_bunny_720p_stereo.avi create mode 100644 big_buck_bunny_720p_stereo.ogg create mode 100644 enwik9.zip create mode 100644 normal_file.txt create mode 100644 rdf-files.tar.zip real 0m0.327s user 0m0.016s sys 0m0.027s
Push Changes To The Bare Repository
The files are ready to be pushed to the bare repository.
Only normal_file.txt
will be handled normally,
while the others will be handled as large files.
mslinn@bear bare_repo1 $ time git push -u origin master Locking support detected on remote "origin". Consider enabling it with: $ git config lfs.https://gojira/home/mslinn/bare_repo1.git/info/lfs.locksverify true Uploading LFS objects: 100% (10/10), 2.1 GB | 115 MB/s, done. Enumerating objects: 14, done. Counting objects: 100% (14/14), done. Delta compression using up to 24 threads Compressing objects: 100% (13/13), done. Writing objects: 100% (14/14), 1.93 KiB | 123.00 KiB/s, done. Total 14 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) To ssh://gojira/home/mslinn/bare_repo1 * [new branch] master -> master branch 'master' set up to track 'origin/master'. real 0m19.457s user 0m3.541s sys 0m3.557s
That happened quickly!
I do not believe the Locking support detected
message since http
is not being used.
If you type the git config
command as suggested, the warning goes away, which is fine,
but nothing changes unless http
is used.
The above pushed LFS objects to gojira:/home/mslinn/bare_repo1/.git/lfs/objects
.
We can see the same IDs for the large files
in both copies of the repository.
mslinn@bear bare_repo1 $ tree .git/lfs/ .git/lfs/ .git/lfs/ ├── cache │ └── locks │ └── refs │ └── heads │ └── master │ └── verifiable ├── objects │ ├── 45 │ │ └── c8 │ │ └── 45c8bafeb9a53df7f491198d2e71529701bcf1cd51805782089fac1d32869f9b │ ├── 4f │ │ └── c7 │ │ └── 4fc75fa403994e7c313da139d93a5aebdbda27cc951616aa4e480db6877c9850 │ ├── 73 │ │ └── 8e │ │ └── 738e2f999860553d056dd79c952f58f63cbb73892a57c72342ce9e5330d9d2d7 │ ├── 78 │ │ └── 5b │ │ └── 785b09a585be55f81326a3fcef2cdeeb7ebbc33932b6305fd84209928df67f28 │ ├── 91 │ │ └── 9e │ │ └── 919e19d85c51e8f07074f9e51127c103280d7623c2b6696f2621b4fca6850e76 │ ├── 98 │ │ └── 95 │ │ └── 98959d8b270c6c35c9e2c906559a47c49a0e1491c8c1d6e5576164f3549aeea6 │ ├── 99 │ │ └── cd │ │ └── 99cdb5ac84392252d3f0912ccedd195bc95bd80cbef3b0cdf2eee4ad9a3b7a51 │ ├── 9b │ │ └── 98 │ │ └── 9b9867582cc9cf88b03f8a2065c4f86ec17e650e65c369e1ea4d0d37e5df5da6 │ ├── c5 │ │ └── 60 │ │ └── c5608dae76ef836dfe8af2651d3869a2db0c3a9015ac43fb8d17f72499d17c58 │ └── d1 │ └── 4b │ └── d14b73150642f30d2342e6620fa537ea273a58b8b751fc5af8f4aabe809f8fc4 └── tmp 28 directories, 11 files
The same files exist in the .git/lfs/objects
directory on the server.
mslinn@bear bare_repo1 $ ssh gojira tree bare_repo1/.git/lfs/objects bare_repo1/.git/lfs/objects ├── 45 │ └── c8 │ └── 45c8bafeb9a53df7f491198d2e71529701bcf1cd51805782089fac1d32869f9b ├── 4f │ └── c7 │ └── 4fc75fa403994e7c313da139d93a5aebdbda27cc951616aa4e480db6877c9850 ├── 73 │ └── 8e │ └── 738e2f999860553d056dd79c952f58f63cbb73892a57c72342ce9e5330d9d2d7 ├── 78 │ └── 5b │ └── 785b09a585be55f81326a3fcef2cdeeb7ebbc33932b6305fd84209928df67f28 ├── 91 │ └── 9e │ └── 919e19d85c51e8f07074f9e51127c103280d7623c2b6696f2621b4fca6850e76 ├── 98 │ └── 95 │ └── 98959d8b270c6c35c9e2c906559a47c49a0e1491c8c1d6e5576164f3549aeea6 ├── 99 │ └── cd │ └── 99cdb5ac84392252d3f0912ccedd195bc95bd80cbef3b0cdf2eee4ad9a3b7a51 ├── 9b │ └── 98 │ └── 9b9867582cc9cf88b03f8a2065c4f86ec17e650e65c369e1ea4d0d37e5df5da6 ├── c5 │ └── 60 │ └── c5608dae76ef836dfe8af2651d3869a2db0c3a9015ac43fb8d17f72499d17c58 └── d1 └── 4b └── d14b73150642f30d2342e6620fa537ea273a58b8b751fc5af8f4aabe809f8fc4
21 directories, 10 files
Clone The Bare Repository Again
Scenario 3: GitHub With Locally Accessible Large Files
Scenario | Git Server | Git LFS Protocol | Use Cases |
---|---|---|---|
3 | GitHub | Local (file )
|
|
Scenario 4: GitHub With Remotely Accessible Large Files Over SSH
Scenario | Git Server | Git LFS Protocol | Use Cases |
---|---|---|---|
4 | GitHub | SSH |
|
Scenario | Git Server | Git LFS Protocol | Use Cases |
---|---|---|---|
5 | GitHub | http
|
|
I have published 7 articles about the Git large file system (LFS). They are meant to be read in order.
- Git Large File System Overview
- Git LFS Client Installation
- Git LFS Server URLs
- Git-ls-files and Wildmatch
- Git LFS Filename Patterns & Tracking
- Git LFS Client Configuration & Commands
- Working With Git LFS
- Evaluation Procedure For Git LFS Servers
- Git LFS server tests:
6 articles are still in process.
Instructions for typing along are given for Ubuntu and WSL/Ubuntu. If you have a Mac, most of this information should be helpful.