Git Large File Storage
Git Large File Storage (or LFS) is a new, open-source extension to Git that aims to improve handling of large files. It does this by replacing large files in your repository—such as graphics—with simple text pointers.
Bitbucket Server includes an embedded LFS object store, allowing storage of large files without the need for an external object store.
Git LFS is disabled by default, on a per-repository basis, within Bitbucket Server.
- SSL should be configured and the Base URL should be configured to a "https" URL. While Git LFS does support SSH remotes, the actual download and upload of LFS objects is via HTTP(S). SSL configuration is not a requirement but is strongly recommended.
The user running the Bitbucket Server instance should not have the Git LFS client executable installed.
Enabling Git LFS for a repository
Git LFS is disabled by default within Bitbucket Server.
To enable Git LFS for Bitbucket Server
- Go to Repository settings > Large file storage (LFS)
- Tick the Allow LFS option.
- Save your settings.
If the Allow LFS tick box is un-selectable (greyed out) this is because the instance administrator has disabled LFS support on the instance.
Installing and using the Git LFS command line client
Git LFS aims to integrate with the standard Git workflow as seamlessly as possible.
To push your first Git LFS files to an existing repository
- Enable Git LFS support in Bitbucket Server for repository you wish to use Git LFS (see above)
- Download and install the git-lfs command line client
Install the Git LFS filters:
git lfs install
This adds the following lines to the
.gitconfigfile located in your home directory:
[filter "lfs"] clean = git-lfs clean %f smudge = git-lfs smudge %f required = true
The above change applies globally, so it is not necessary to run this for each repository you work with.
Choose the file types you would like LFS to handle by executing the
git lfs trackcommand. The
git lfs trackcommand creates or updates the
.gitattributesfile in your repository.
Change to your cloned repository, then execute
git addto ensure updates to the
.gitattributesare later committed:
git lfs track "*.jpg" git add .gitattributes
Add, commit, and push your changes as you normally would:
git add image.jpg git commit -m "Added an image" git push
When pushed, the Git tree updates to include a pointer to the actual file content. This pointer will include the SHA256 hash of the object and its size in bytes. For example:
oid sha256:4fa32d6f9b1461c4a53618a47324e243e36ce7ceae72ad440cc811a7e6881be1 size 1580060
The object itself will be uploaded to a separate location via the Git LFS Batch API. Specifically, the object will be uploaded to an embedded LFS object store within your Bitbucket Server instance.
Disabling Git LFS for Bitbucket Server
Bitbucket Server is shipped with Git LFS support enabled on the instance by default, however it can be disabled. This will prevent upload or download of LFS objects for all repositories. It however does not delete existing LFS objects stored within Bitbucket Server.
To disable Git LFS on the entire Bitbucket Server instance
- Log in to Bitbucket Server with sysadmin permissions.
- Go to Admin > Server settings.
- Untick the Git LFS enabled option.
- Save your settings.
Embedded Object Store
Bitbucket Server includes an embedded LFS object store. Uploaded Git LFS objects are stored in the directory
$BITBUCKET_HOME/shared/data/git-lfs/storage. This storage location cannot be changed, as for clustered deployments it is critical that LFS object storage reside on the
shared filesystem so it is globally visible to all cluster nodes.
LFS enabled repositories support forking and a full fork-based workflow including pull requests between forks and fork synchronization. Forking is implemented through sharing of objects between fork and origin repositories and as such forks are lightweight. This means creating a fork is faster because objects are not duplicated when a fork is created.
Resolution of merge conflicts is slightly different from the non-LFS case, specifically where a merge conflict exists between two LFS objects. Since the Git repository simply contains an LFS pointer, conflict resolution must be performed with the conflicted pointer file.
Such a conflict might look like this:
Users are still required to resolve the merge conflict manually using the command line Git client, as they normally would. The merge strategy, since this is only a pointer, can only be an ours or theirs based strategy, keeping one or the two pairs (oid/size). When resolving the conflict, if the pointer file becomes corrupted it will not be recognized as an LFS file.
The Smart Mirroring feature in Bitbucket Server supports mirroring of Git LFS objects as of Bitbucket Server 4.5. Mirroring of Git LFS objects is performed on-demand; that is, when a client requests download of a Git LFS object from the mirror node, the object will be streamed from the upstream node if it is not already available on the mirror. Subsequent downloads of the same object will be downloaded directly from the copy stored on the mirror.
Limiting Disk Space Usage
By default Bitbucket Server will not permit any further Git LFS uploads if the amount of free disk space in the filesystem that hosts the storage directory has less than 100 megabytes of free disk space. When a client attempts to upload (via a Git push) an LFS file that would result in the free disk-space threshold being exceeded, an error message indicating as such is sent to the client:
$ git push Git LFS: (0 of 1 files, 1 skipped) 0 B / 348.59 MB, 348.59 MB skipped [a39717817507d0ae3434a36347159e4970aec061c8c506f197c0eeadd2e8efe2] Insufficient free space in store error: failed to push some refs to 'https://bitbucket.example.com/bitbucket/scm/myproject/myrepo.git'
A warning will also be logged in the
atlassian-bitbucket.log file. For example:
2016-01-01 18:00:00 WARN [http-nio-7990-exec-2] user @G6I7R6x969x556x0 0:0:0:0:0:0:0:1 "POST /scm/myproject/myrepo.git/info/lfs/objects/batch HTTP/1.1" c.a.b.i.s.g.l.s.e.EmbeddedStoreAccessor Upload rejected due to insufficient free space in store - Required: 1073741824 Free: 10485760
The free disk-space threshold can be tuned by adding the following property to the Bitbucket Server config properties file (this example tunes the threshold to one gigabyte, and note that this value is in bytes):
Setting the value to zero will disable the free disk space check and will allow files to be uploaded even if doing so would exhaust all available disk space. This however is not encouraged, it can lead to situations where the system exhausts all disk space but is unable to log error messages stating the same (because the disk is full), leading to difficulties debugging problems that are caused by disk space exhaustion.
A Bitbucket Server restart is required for the change to take effect.
Limiting Network Connections
Large Git LFS download or upload operations over very slow network links could take many minutes, or even hours. Bitbucket Server supports a finite number of HTTP connections (by default 200). If Git LFS were permitted to exhaust this connection pool then the user interface, Git hosting, and REST API access could be impacted. For this reason a default limit of 80 concurrent Git LFS connections are permitted. This limit can be increased or decreased if necessary by overriding the
throttle.resource.git-lfs= setting in the Bitbucket Server config properties file. A Bitbucket Server restart is required for the change to take effect.
When a client makes a request to upload or download an object, and the request would exceed the maximum number of concurrent connections, a HTTP status 503 is returned, and this error is sent to the client:
The requested resource is busy and cannot service your request. Please try again later
atlassian-bitbucket.log file will also contain an associated warning:
2016-01-01 18:00:00 WARN [http-nio-7990-exec-3] username @1HJ1OF1x1115x417x1 0:0:0:0:0:0:0:1 "GET /rest/git-lfs/storage/myproject/myrepo/3a9219fde5bc436a2fc37cdd38bdb8478a210c7a49405dd9603ccdc95ed39613 HTTP/1.1" c.a.s.i.t.SemaphoreThrottleService A [git-lfs] ticket could not be acquired (0/80)