Introduction
git-lfs, implemented in Rust. A from-scratch port of
Git LFS, aiming for feature parity
with the upstream Go binary at the CLI and wire-protocol level — with a
cleaner library split and friendlier help output along the way.
These docs are split into three parts. Protocol & format mirrors the
vendored upstream specs (pointer files, batch API, locking, custom
transfer adapters, extensions). Commands and Plumbing are the
per-command reference. Hooks
documents the post-* / pre-push shims that git lfs install drops
into .git/hooks/.
The implementation is still in progress; see the project README for an up-to-date snapshot of what works.
Git is a trademark of the Software Freedom Conservancy.
Installation
git-lfs ships three ways: as native packages for the major Linux
distributions, as a Homebrew tap (Linux + macOS), and as a Rust crate
on crates.io. Pick the one that matches your platform.
Homebrew (Linux and macOS)
brew tap rustutils/tap
brew install rustutils/tap/git-lfs
APT (Debian and Ubuntu)
Add the signing key, register the repository, and install:
sudo install -d -m 0755 /etc/apt/keyrings
sudo curl -fsSLo /etc/apt/keyrings/rustutils.asc https://rustutils.gitlab.io/apt/rustutils.asc
echo "deb [signed-by=/etc/apt/keyrings/rustutils.asc] https://rustutils.gitlab.io/apt stable main" \
| sudo tee /etc/apt/sources.list.d/rustutils.list
sudo apt update
sudo apt install git-lfs-rs
The package is named git-lfs-rs to avoid colliding with the upstream
Go git-lfs package in Debian. The binary is still called git-lfs, and
installing it will replace git-lfs if you have it installed (but you can
always install git-lfs to go back to it).
RPM (Fedora, RHEL, Rocky, AlmaLinux)
sudo curl -fsSLo /etc/yum.repos.d/rustutils.repo https://rustutils.gitlab.io/rpm/rustutils.repo
sudo dnf install git-lfs-rs
Same git-lfs-rs naming convention.
Cargo (any platform with a Rust toolchain)
cargo install git-lfs
This drops a git-lfs binary into ~/.cargo/bin/. Make sure that
directory is on your PATH so git can find the executable when it
shells out to invoke filters and hooks.
After installing
Run once per machine to register the clean, smudge, and process filters in your global git config:
git lfs install
From there on, git lfs <command> works in any repo with a
.gitattributes that tracks files via LFS. Per-repository hook
installation happens automatically the first time you run an
LFS-aware command in a new clone, no need to re-run git lfs install
per repo.
To enable Git LFS in a repository, you can tell it to track specific files. For example:
# track all PDF files in this repository
git lfs track *.pdf
# track all JPEG images in this repository
git lfs track *.jpg
Git LFS Specification
This is a general guide for Git LFS clients. Typically it should be
implemented by a command line git-lfs tool, but the details may be useful
for other tools.
The Pointer
The core Git LFS idea is that instead of writing large blobs to a Git repository, only a pointer file is written.
- Pointer files are text files which MUST contain only UTF-8 characters.
- Each line MUST be of the format
{key} {value}\n(trailing unix newline). - Only a single space character between
{key}and{value}. - Keys MUST only use the characters
[a-z] [0-9] . -. - The first key is always
version. - Lines of key/value pairs MUST be sorted alphabetically in ascending order
(with the exception of
version, which is always first). - Values MUST NOT contain return or newline characters.
- Pointer files MUST be stored in Git with their executable bit matching that of the replaced file.
- Pointer files must be less than 1024 bytes in size, including any pointer extension lines.
- Pointer files are unique: that is, there is exactly one valid encoding for a pointer file.
An empty file is the pointer for an empty file. That is, empty files are passed through LFS without any change.
The required keys are:
versionis a URL that identifies the pointer file spec. Parsers MUST use simple string comparison on the version, without any URL parsing or normalization. It is case sensitive, and %-encoding is discouraged.oidtracks the unique object id for the file, prefixed by its hashing method:{hash-method}:{hash}. Currently, onlysha256is supported. The hash is lower case hexadecimal.sizeis in bytes.
Example of a v1 text pointer:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345
(ending \n)
Blobs created with the pre-release version of the tool generated files with a different version URL. Git LFS can read these files, but writes them using the version URL above.
version https://hawser.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345
(ending \n)
For testing compliance of any tool generating its own pointer files, the reference is this official Git LFS tool:
NOTE: exact pointer command behavior TBD!
-
Tools that parse and regenerate pointer files MUST preserve keys that they don’t know or care about.
-
Run the
pointercommand to generate a pointer file for the given local file:$ git lfs pointer --file=path/to/file Git LFS pointer for path/to/file: version https://git-lfs.github.com/spec/v1 oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393 size 12345 -
Run
pointerto compare the blob OID of a pointer file built by Git LFS with a pointer built by another tool.-
Write the other implementation’s pointer to “other/pointer/file”:
$ git lfs pointer --file=path/to/file --pointer=other/pointer/file Git LFS pointer for path/to/file: version https://git-lfs.github.com/spec/v1 oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393 size 12345 Blob OID: 60c8d8ab2adcf57a391163a7eeb0cdb8bf348e44 Pointer from other/pointer/file version https://git-lfs.github.com/spec/v1 oid sha256 4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393 size 12345 Blob OID: 08e593eeaa1b6032e971684825b4b60517e0638d Pointers do not match -
It can also read STDIN to get the other implementation’s pointer:
$ cat other/pointer/file | git lfs pointer --file=path/to/file --stdin Git LFS pointer for path/to/file: version https://git-lfs.github.com/spec/v1 oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393 size 12345 Blob OID: 60c8d8ab2adcf57a391163a7eeb0cdb8bf348e44 Pointer from STDIN version https://git-lfs.github.com/spec/v1 oid sha256 4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393 size 12345 Blob OID: 08e593eeaa1b6032e971684825b4b60517e0638d Pointers do not match
-
Intercepting Git
Git LFS uses the clean and smudge filters to decide which files use it. The
global filters can be set up with git lfs install:
$ git lfs install
These filters ensure that large files aren’t written into the repository proper,
instead being stored locally at .git/lfs/objects/{OID-PATH} (where {OID-PATH}
is a sharded filepath of the form OID[0:2]/OID[2:4]/OID), synchronized with
the Git LFS server as necessary. Here is a sample path to a file:
.git/lfs/objects/4d/7a/4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
The clean filter runs as files are added to repositories. Git sends the
content of the file being added as STDIN, and expects the content to write
to Git as STDOUT.
- Stream binary content from STDIN to a temp file, while calculating its SHA-256 signature.
- Atomically move the temp file to
.git/lfs/objects/{OID-PATH}if it does not exist, and the sha-256 signature of the contents matches the given OID. - Delete the temp file.
- Write the pointer file to STDOUT.
Note that the clean filter does not push the file to the server. Use the
git push command to do that (lfs files are pushed before commits in a pre-push hook).
The smudge filter runs as files are being checked out from the Git repository
to the working directory. Git sends the content of the Git blob as STDIN, and
expects the content to write to the working directory as STDOUT.
- Read 100 bytes.
- If the content is ASCII and matches the pointer file format:
- Look for the file in
.git/lfs/objects/{OID-PATH}. - If it’s not there, download it from the server.
- Write its contents to STDOUT
- Look for the file in
- Otherwise, simply pass the STDIN out through STDOUT.
The .gitattributes file controls when the filters run. Here’s a sample file that
runs all mp3 and zip files through Git LFS:
$ cat .gitattributes
*.mp3 filter=lfs -text
*.zip filter=lfs -text
Use the git lfs track command to view and add to .gitattributes.
Adding Custom Transfer Agents to LFS
Introduction
Git LFS supports multiple ways to transfer (upload and download) files. In the
core client, the basic way to do this is via a one-off HTTP request via the URL
returned from the LFS API for a given object. The core client also supports
extensions to allow resuming of downloads (via Range headers) and uploads (via
the tus.io protocol).
Some people might want to be able to transfer content in other ways, however. To enable this, git-lfs allows configuring Custom Transfers, which are simply processes which must adhere to the protocol defined later in this document. git-lfs will invoke the process at the start of all transfers, and will communicate with the process via stdin/stdout for each transfer.
Custom Transfer Type Selection
In the LFS API request, the client includes a list of transfer types it supports. When replying, the API server will pick one of these and make any necessary adjustments to the returned object actions, in case the picked transfer type needs custom details about how to do each transfer.
Using a Custom Transfer Type without the API server
In some cases the transfer agent can figure out by itself how and where the transfers should be made, without having to query the API server. In this case it’s possible to use the custom transfer agent directly, without querying the server, by using the following config option:
-
lfs.standalonetransferagent,lfs.<url>.standalonetransferagentSpecifies a custom transfer agent to be used if the API server URL matches as in
git config --get-urlmatch lfs.standalonetransferagent <apiurl>.git-lfswill not contact the API server. It instead sets stage 2 transfer actions tonull.lfs.<url>.standalonetransferagentcan be used to configure a custom transfer agent for individual remotes.lfs.standalonetransferagentunconditionally configures a custom transfer agent for all remotes. The custom transfer agent must be specified in alfs.customtransfer.<name>settings group.
Defining a Custom Transfer Type
A custom transfer process is defined under a settings group called
lfs.customtransfer.<name>, where <name> is an identifier (see
Naming below).
-
lfs.customtransfer.<name>.pathpathshould point to the process you wish to invoke. This will be invoked at the start of all transfers (possibly many times, see theconcurrentoption below) and the protocol over stdin/stdout is defined below in the Protocol section. -
lfs.customtransfer.<name>.argsIf the custom transfer process requires any arguments, these can be provided here. Typically you would only need this if your process was multi-purpose or particularly flexible, most of the time you won’t need it. Note that this string will be expanded by the shell.
-
lfs.customtransfer.<name>.concurrentIf true (the default), git-lfs will invoke the custom transfer process multiple times in parallel, according to
lfs.concurrenttransfers, splitting the transfer workload between the processes.If you would prefer that only one instance of the transfer process is invoked, maybe because you want to do your own parallelism internally (e.g. slicing files into parts), set this to false.
-
lfs.customtransfer.<name>.directionSpecifies which direction the custom transfer process supports, either
download,upload, orboth. The default if unspecified isboth.
Naming
Each custom transfer must have a name which is unique to the underlying mechanism, and the client and the server must agree on that name. The client will advertise this name to the server as a supported transfer approach, and if the server supports it, it will return relevant object action links. Because these may be very different from standard HTTP URLs it’s important that the client and server agree on the name.
For example, let’s say I’ve implemented a custom transfer process which uses
NFS. I could call this transfer type nfs - although it’s not specific to my
configuration exactly, it is specific to the way NFS works, and the server will
need to give me different URLs. Assuming I define my transfer like this, and the
server supports it, I might start getting object action links back like
nfs://<host>/path/to/object
Protocol
The git-lfs client communicates with the custom transfer process via the stdin and stdout streams. No file content is communicated on these streams, only request / response metadata. The metadata exchanged is always in JSON format. External files will be referenced when actual content is exchanged.
Line Delimited JSON
Because multiple JSON messages will be exchanged on the same stream it’s useful
to delimit them explicitly rather than have the parser find the closing } in
an arbitrary stream, therefore each JSON structure will be sent and received on
a single line as per Line Delimited
JSON.
In other words when git-lfs sends a JSON message to the custom transfer it will be on a single line, with a line feed at the end. The transfer process must respond the same way by writing a JSON structure back to stdout with a single line feed at the end (and flush the output).
Protocol Stages
The protocol consists of 3 stages:
Stage 1: Initiation
Immediately after invoking a custom transfer process, git-lfs sends initiation data to the process over stdin. This tells the process useful information about the configuration.
The message will look like this:
{ "event": "init", "operation": "download", "remote": "origin", "concurrent": true, "concurrenttransfers": 3 }
event: Alwaysinitto identify this messageoperation: will beuploadordownloaddepending on transfer directionremote: The Git remote. It can be a remote name likeoriginor an URL likessh://git.example.com//path/to/repo. A standalone transfer agent can use it to determine the location of remote files.concurrent: reflects the value oflfs.customtransfer.<name>.concurrent, in case the process needs to knowconcurrenttransfers: reflects the value oflfs.concurrenttransfers, for if the transfer process wants to implement its own concurrency and wants to respect this setting.
The transfer process should use the information it needs from the initiation structure, and also perform any one-off setup tasks it needs to do. It should then respond on stdout with a simple empty confirmation structure, as follows:
{ }
Or if there was an error:
{ "error": { "code": 32, "message": "Some init failure message" } }
Stage 2: 0..N Transfers
After the initiation exchange, git-lfs will send any number of transfer requests to the stdin of the transfer process, in a serial sequence. Once a transfer request is sent to the process, it awaits a completion response before sending the next request.
Uploads
For uploads the request sent from git-lfs to the transfer process will look like this:
{ "event": "upload", "oid": "bf3e3e2af9366a3b704ae0c31de5afa64193ebabffde2091936ad2e7510bc03a", "size": 346232, "path": "/path/to/file.png", "action": { "href": "nfs://server/path", "header": { "key": "value" } } }
event: Alwaysuploadto identify this messageoid: the identifier of the LFS objectsize: the size of the LFS objectpath: the file which the transfer process should read the upload data fromaction: theuploadaction copied from the response from the batch API. This containshrefandheadercontents, which are named per HTTP conventions, but can be interpreted however the custom transfer agent wishes (this is an NFS example, but it doesn’t even have to be an URL). Generally,hrefwill give the primary connection details, withheadercontaining any miscellaneous information needed.actionisnullfor standalone transfer agents.
The transfer process should post one or more progress messages and then a final completion message as follows:
{ "event": "complete", "oid": "bf3e3e2af9366a3b704ae0c31de5afa64193ebabffde2091936ad2e7510bc03a" }
event: Alwayscompleteto identify this messageoid: the identifier of the LFS object
Or if there was an error in the transfer:
{ "event": "complete", "oid": "bf3e3e2af9366a3b704ae0c31de5afa64193ebabffde2091936ad2e7510bc03a", "error": { "code": 2, "message": "Explain what happened to this transfer" } }
event: Alwayscompleteto identify this messageoid: the identifier of the LFS objecterror: Should contain acodeandmessageexplaining the error
Downloads
For downloads the request sent from git-lfs to the transfer process will look like this:
{ "event": "download", "oid": "22ab5f63670800cc7be06dbed816012b0dc411e774754c7579467d2536a9cf3e", "size": 21245, "action": { "href": "nfs://server/path", "header": { "key": "value" } } }
event: Alwaysdownloadto identify this messageoid: the identifier of the LFS objectsize: the size of the LFS objectaction: thedownloadaction copied from the response from the batch API. This containshrefandheadercontents, which are named per HTTP conventions, but can be interpreted however the custom transfer agent wishes (this is an NFS example, but it doesn’t even have to be an URL). Generally,hrefwill give the primary connection details, withheadercontaining any miscellaneous information needed.actionisnullfor standalone transfer agents.
Note there is no file path included in the download request; the transfer process should create a file itself and return the path in the final response after completion (see below).
The transfer process should post one or more progress messages and then a final completion message as follows:
{ "event": "complete", "oid": "22ab5f63670800cc7be06dbed816012b0dc411e774754c7579467d2536a9cf3e", "path": "/path/to/file.png" }
event: Alwayscompleteto identify this messageoid: the identifier of the LFS objectpath: the path to a file containing the downloaded data, which the transfer process relinquishes control of to git-lfs. git-lfs will move the file into LFS storage.
Or, if there was a failure transferring this item:
{ "event": "complete", "oid": "22ab5f63670800cc7be06dbed816012b0dc411e774754c7579467d2536a9cf3e", "error": { "code": 2, "message": "Explain what happened to this transfer" } }
event: Alwayscompleteto identify this messageoid: the identifier of the LFS objecterror: Should contain acodeandmessageexplaining the error
Errors for a single transfer request should not terminate the process. The error should be returned in the response structure instead.
The custom transfer adapter does not need to check the SHA of the file content it has downloaded, git-lfs will do that before moving the final content into the LFS store.
Progress
In order to support progress reporting while data is uploading / downloading, the transfer process should post messages to stdout as follows before sending the final completion message:
{ "event": "progress", "oid": "22ab5f63670800cc7be06dbed816012b0dc411e774754c7579467d2536a9cf3e", "bytesSoFar": 1234, "bytesSinceLast": 64 }
event: Alwaysprogressto identify this messageoid: the identifier of the LFS objectbytesSoFar: the total number of bytes transferred so farbytesSinceLast: the number of bytes transferred since the last progress message
The transfer process should post these messages such that the last one sent
has bytesSoFar equal to the file size on success.
Stage 3: Finish & Cleanup
When all transfers have been processed, git-lfs will send the following message to the stdin of the transfer process:
{ "event": "terminate" }
On receiving this message the transfer process should clean up and terminate. No response is expected.
Error handling
Any unexpected fatal errors in the transfer process (not errors specific to a transfer request) should set the exit code to non-zero and print information to stderr. Otherwise the exit code should be 0 even if some transfers failed.
A Note On Verify Actions
You may have noticed that that only the upload and download actions are
passed to the custom transfer agent for processing, what about the verify
action, if the API returns one?
Custom transfer agents do not handle the verification process, only the upload and download of content. The verify link is typically used to notify a system other than the actual content store after an upload was completed, therefore it makes more sense for that to be handled via the normal API process.
Extending LFS
Teams who use Git LFS often have custom requirements for how the pointer files and blobs should be handled. Some examples of extensions that could be built:
- Compress large files on clean, uncompress them on smudge/fetch
- Encrypt files on clean, decrypt on smudge/fetch
- Scan files on clean to make sure they don’t contain sensitive information
The basic extensibility model is that LFS extensions must be registered explicitly, and they will be invoked on clean and smudge to manipulate the contents of the files as needed. On clean, LFS itself ensures that the pointer file is updated with all the information needed to be able to smudge correctly, and the extensions never modify the pointer file directly.
NOTE: This feature is considered experimental, and included so developers can work on extensions. Exact details of how extensions work are subject to change based on feedback. It is possible for buggy extensions to leave your repository in a bad state, so don’t rely on them with a production git repository without extensive testing.
Registration
To register an LFS extension, it must be added to the Git config. Each extension needs to define:
- Its unique name. This will be used as part of the key in the pointer file.
- The command to run on clean (when files are added to git).
- The command to run on smudge (when files are downloaded and checked out).
- The priority of the extension, which must be a unique, non-negative integer.
The sequence %f in the clean and smudge commands will be replaced by the
filename being processed.
Here’s an example extension registration in the Git config:
[lfs "extension.foo"]
clean = foo clean %f
smudge = foo smudge %f
priority = 0
[lfs "extension.bar"]
clean = bar clean %f
smudge = bar smudge %f
priority = 1
Clean
When staging a file, Git invokes the LFS clean filter, as described earlier. If no extensions are installed, the LFS clean filter reads bytes from STDIN, calculates the SHA-256 signature, and writes the bytes to a temp file. It then moves the temp file into the appropriate place in .git/lfs/objects and writes a valid pointer file to STDOUT.
When an extension is installed, LFS will invoke the extension to do additional processing on the bytes before writing them into the temp file. If multiple extensions are installed, they are invoked in the order defined by their priority. LFS will also insert a key in the pointer file for each extension that was invoked, indicating both the order that the extension was invoked and the oid of the file before that extension was invoked. All of that information is required to be able to reliably smudge the file later. Each new line in the pointer file will be of the form:
ext-{order}-{name} {hash-method}:{hash-of-input-to-extension}
This naming ensures that all extensions are written in both alphabetical and priority order, and also shows the progression of changes to the oid as it is processed by the extensions.
Here’s an example sequence, assuming extensions foo and bar are installed, as shown in the previous section.
- Git passes the original contents of the file to LFS clean over STDIN.
- LFS reads those bytes and calculates the original SHA-256 signature.
- LFS streams the bytes to STDIN of
foo clean, which is expected to write those bytes, modified or not, to its STDOUT. - LFS reads the bytes from STDOUT of
foo clean, calculates the SHA-256 signature, and writes them to STDIN ofbar clean, which then writes those bytes, modified or not, to its STDOUT. - LFS reads the bytes from STDOUT of
bar clean, calculates the SHA-256 signature, and writes the bytes to a temp file. - When finished, LFS atomically moves the temp file into
.git/lfs/objects. - LFS generates the pointer file, with some changes:
- The oid and size keys are calculated from the final bytes written to LFS local storage.
- LFS also writes keys named
ext-0-fooandext-1-barinto the pointer, along with their respective input oids.
Here’s an example pointer file, for a file processed by extensions foo and bar:
version https://git-lfs.github.com/spec/v1
ext-0-foo sha256:{original hash}
ext-1-bar sha256:{hash after foo}
oid sha256:{hash after bar}
size 123
(ending \n)
Note: as an optimization, if an extension just does a pass-through, its key can be omitted from the pointer file. This will make smudging the file a bit more efficient since that extension can be skipped. LFS can detect a pass-through extension because the input and output oids will be the same.
This implies that extensions must have no side effects other than writing to their STDOUT. Otherwise LFS has no way to know what extensions modified a file.
Smudge
When a file is checked out, Git invokes the LFS smudge filter, as described earlier. If no extensions are installed, the LFS smudge filter inspects the first 100 bytes of the bytes off STDIN, and if it is a pointer file, uses the oid to find the correct object in the LFS storage, and writes those bytes to STDOUT so that Git can write them to the working directory.
If the pointer file indicates that extensions were invoked on that file, then those extensions must be installed in order to smudge. If they are not installed, not found, or unusable for any reason, LFS will fail to smudge the file, and outputs an error indicating which extension is missing.
Each of the extensions indicated in the pointer file must be invoked in reverse order to undo the changes they made to the contents of the file. After each extension is invoked, LFS will compare the SHA-256 signature of the bytes output by the extension with the oid stored in the pointer file as the original input to that same extension. Those signatures must match, otherwise the extension did not undo its changes correctly. In that case, LFS fails to smudge the file, and outputs an error indicating which extension is failing.
Here’s an example sequence, indicating how LFS will smudge the pointer file shown in the previous section:
- Git passes the bytes of the pointer file to LFS smudge over STDIN. Note that
when using
git lfs checkout, LFS reads the files directly from disk rather than off STDIN. The rest of the steps are unaffected either way. - LFS reads those bytes and inspects them to see if this is a pointer file. If it was not, the bytes would just be passed through to STDOUT.
- Since it is a pointer file, LFS reads the whole file off STDIN, parses it, and determines that extensions foo and bar both processed the file, in that order.
- LFS uses the value of the oid key to find the blob in the
.git/lfs/objectsfolder, or download from the server as needed. - LFS writes the contents of the blob to STDIN of
bar smudge, which modifies them as needed and writes them to its STDOUT. - LFS reads the bytes from STDOUT of
bar smudge, calculates the SHA-256 signature, and writes the bytes to STDIN offoo smudge, which modifies them as needed and writes to them its STDOUT. - LFS reads the bytes from STDOUT of
foo smudge, calculates the SHA-256 signature, and writes the bytes to its own STDOUT. - At the end, ensure that the hashes calculated on the outputs of foo and bar match their corresponding input hashes from the pointer file. If not, write a descriptive error message indicating which extension failed to undo its changes.
- Question: On error, should we overwrite the file in the working directory with the original pointer file? Can this be done reliably?
Handling errors
If there are errors in the configuration of LFS extensions, such as invalid extension names, duplicate priorities, etc, then any LFS commands that rely on them will abort with a descriptive error message.
If an extension is unable to perform its task, it can indicate this error by returning a non-zero error code and writing a descriptive error message to its STDERR. The behavior on an error depends on whether we are cleaning or smudging.
Clean
If an extension fails to clean a file, it will return a non-zero error code and write an error message to its STDERR. Because the file was not cleaned correctly, it can’t be added to the index. LFS will ensure that no pointer file is added or updated for failed files. In addition, it will display the error messages for any files that could not be cleaned (and keep those errors in a log), so that the user can diagnose the failure, and then rerun “git add” on those files.
Smudge
If an extension fails to smudge a file, it will return a non-zero error code and
write an error message to its STDERR. Because the file was not smudged
correctly, LFS cannot update that file in the working directory. LFS will
ensure that the pointer file is written to both the index and working directory.
In addition, it will display the error messages for any files that could not be
smudged (and keep those errors in a log), so that the user can diagnose the
failure and then rerun git-lfs checkout to fix up any remaining pointer files.
Git LFS API
The Git LFS client uses an HTTPS server to coordinate fetching and storing large binary objects separately from a Git server. The basic process the client goes through looks like this:
- Discover the LFS Server to use.
- Apply Authentication.
- Make the request. See the Batch and File Locking API sections.
Batch API
The Batch API is used to request the ability to transfer LFS objects with the LFS server.
API Specification:
Current transfer adapters include:
Experimental transfer adapters include:
- Tus.io (upload only)
- Custom
File Locking API
The File Locking API is used to create, list, and delete locks, as well as verify that locks are respected in Git pushes.
API Specification:
Server Discovery
One of the Git LFS goals is to work with supporting Git remotes with as few required configuration properties as possible. Git LFS will attempt to use your Git remote to determine the LFS server. You can also configure a custom LFS server if your Git remote doesn’t support one, or you just want to use a separate one.
Look for the Endpoint properties in git lfs env to see your current LFS
servers.
Guessing the Server
By default, Git LFS will append .git/info/lfs to the end of a Git remote url
to build the LFS server URL it will use:
Git Remote: https://git-server.com/foo/bar
LFS Server: https://git-server.com/foo/bar.git/info/lfs
Git Remote: https://git-server.com/foo/bar.git
LFS Server: https://git-server.com/foo/bar.git/info/lfs
Git Remote: git@git-server.com:foo/bar.git
LFS Server: https://git-server.com/foo/bar.git/info/lfs
Git Remote: ssh://git-server.com/foo/bar.git
LFS Server: https://git-server.com/foo/bar.git/info/lfs
SSH
If Git LFS detects an SSH remote, it will run the git-lfs-authenticate
command. This allows supporting Git servers to give the Git LFS client
alternative authentication so the user does not have to setup a git credential
helper.
Git LFS runs the following command:
$ ssh [{user}@]{server} git-lfs-authenticate {path} {operation}
The user, server, and path properties are taken from the SSH remote. The
operation can either be “download” or “upload”. The SSH command can be
tweaked with the GIT_SSH or GIT_SSH_COMMAND environment variables. The
output for successful commands is JSON, and matches the schema as an action
in a Batch API response. Git LFS will dump the STDERR from the ssh command if
it returns a non-zero exit code.
Examples:
The git-lfs-authenticate command can even suggest an LFS endpoint that does
not match the Git remote by specifying an href property.
# Called for remotes like:
# * git@git-server.com:foo/bar.git
# * ssh://git@git-server.com/foo/bar.git
$ ssh git@git-server.com git-lfs-authenticate foo/bar.git download
{
"href": "https://lfs-server.com/foo/bar",
"header": {
"Authorization": "RemoteAuth some-token"
},
"expires_in": 86400
}
Git LFS will output the STDERR if git-lfs-authenticate returns a non-zero
exit code:
$ ssh git@git-server.com git-lfs-authenticate foo/bar.git wat
Invalid LFS operation: "wat"
Custom Configuration
If Git LFS can’t guess your LFS server, or you aren’t using the
git-lfs-authenticate command, you can specify the LFS server using Git config.
Set lfs.url to set the LFS server, regardless of Git remote.
$ git config lfs.url https://lfs-server.com/foo/bar
You can set remote.{name}.lfsurl to set the LFS server for that specific
remote only:
$ git config remote.dev.lfsurl http://lfs-server.dev/foo/bar
$ git lfs env
...
Endpoint=https://git-server.com/foo/bar.git/info/lfs (auth=none)
Endpoint (dev)=http://lfs-server.dev/foo/bar (auth=none)
Git LFS will also read these settings from a .lfsconfig file in the root of
your repository. This lets you commit it to the repository so that all users
can use it, if you wish.
$ git config --file=.lfsconfig lfs.url https://lfs-server.com/foo/bar
Authentication
The Git LFS API uses HTTP Basic Authentication to authorize requests. Therefore, HTTPS is strongly encouraged for all production Git LFS servers. The credentials can come from the following places:
SSH
Git LFS will add any HTTP headers returned from the git-lfs-authenticate
command to any Batch API requests. If servers are returning expiring tokens,
they can add an expires_in (or expires_at) property to hint when the token
will expire.
# Called for remotes like:
# * git@git-server.com:foo/bar.git
# * ssh://git@git-server.com/foo/bar.git
$ ssh git@git-server.com git-lfs-authenticate foo/bar.git download
{
"header": {
"Authorization": "RemoteAuth some-token"
},
# optional, for expiring tokens, preferred over expires_at
"expires_in": 86400,
# optional, for expiring tokens
"expires_at": "2016-11-10T15:29:07Z"
}
See the SSH section in the Server Discovery doc for
more info about git-lfs-authenticate.
Git Credentials
Git provides a credentials command
for storing and retrieving credentials through a customizable credential helper.
By default, it associates the credentials with a domain. You can enable
credential.useHttpPath so different repository paths have different
credentials.
Git ships with a really basic credential cacher that stores passwords in memory, so you don’t have to enter your password frequently. However, you are encouraged to setup a custom git credential cacher, if a better one exists for your platform.
As of version 3.0, Git LFS no longer supports NTLM. Users are encouraged to set up
Kerberos; for example, Azure DevOps Server recommends Kerberos over NTLM in
this blog post.
For pre-3.0 LFS versions, if your Git LFS server authenticates with NTLM then you
must provide your credentials to git-credential in the form
username:DOMAIN\user password:password.
Specified in URL
You can hardcode credentials into your Git remote or LFS url properties in your git config. This is not recommended for security reasons because it relies on the credentials living in your local git config.
$ git remote add origin https://user:password@git-server.com/foo/bar.git
Git LFS Batch API
Added: v0.6
The Batch API is used to request the ability to transfer LFS objects with the
LFS server. The Batch URL is built by adding /objects/batch to the LFS server
URL.
Git remote: https://git-server.com/foo/bar LFS server: https://git-server.com/foo/bar.git/info/lfs Batch API: https://git-server.com/foo/bar.git/info/lfs/objects/batch
See the Server Discovery doc for more info on how LFS builds the LFS server URL.
All Batch API requests use the POST verb, and require the following HTTP headers. The request and response bodies are JSON.
Accept: application/vnd.git-lfs+json
Content-Type: application/vnd.git-lfs+json
The client may also include a charset=utf-8 parameter in the
Content-Type header, which servers should be prepared to accept.
See the Authentication doc for more info on how LFS gets authorizes Batch API requests.
Requests
The client sends the following information to the Batch endpoint to transfer some objects:
operation- Should bedownloadorupload.transfers- An optional Array of String identifiers for transfer adapters that the client has configured. If omitted, thebasictransfer adapter MUST be assumed by the server.ref- Optional object describing the server ref that the objects belong to. Note: Added in v2.4.name- Fully-qualified server refspec.
objects- An Array of objects to download.oid- String OID of the LFS object.size- Integer byte size of the LFS object. Must be at least zero.
hash_algo- The hash algorithm used to name Git LFS objects. Optional; defaults tosha256if not specified.
Note: Git LFS currently only supports the basic transfer adapter. This
property was added for future compatibility with some experimental transfer
adapters. See the API README for a list of the documented
transfer adapters.
// POST https://lfs-server.com/objects/batch
// Accept: application/vnd.git-lfs+json
// Content-Type: application/vnd.git-lfs+json
// Authorization: Basic ... (if needed)
{
"operation": "download",
"transfers": [ "basic" ],
"ref": { "name": "refs/heads/main" },
"objects": [
{
"oid": "12345678",
"size": 123
}
],
"hash_algo": "sha256"
}
Ref Property
The Batch API added the ref property in LFS v2.4 to support Git server authentication schemes that take the refspec into account. Since this is
a new addition to the API, servers should be able to operate with a missing or null ref property.
Some examples will illustrate how the ref property can be used.
- User
ownerhas full access to the repository. - User
contribhas readonly access to the repository, and write access torefs/heads/contrib.
{
"operation": "download",
"transfers": [ "basic" ],
"objects": [
{
"oid": "12345678",
"size": 123
}
]
}
With this payload, both owner and contrib can download the requested object, since they both have read access.
{
"operation": "upload",
"transfers": [ "basic" ],
"objects": [
{
"oid": "12345678",
"size": 123
}
]
}
With this payload, only owner can upload the requested object.
{
"operation": "upload",
"transfers": [ "basic" ],
"ref": { "name": "refs/heads/contrib" },
"objects": [
{
"oid": "12345678",
"size": 123
}
]
}
Both owner and contrib can upload the request object.
Successful Responses
The Batch API should always return with a 200 status, unless there are some issues with the request (bad authorization, bad json, etc). See below for examples of response errors. Check out the documented transfer adapters in the API README to see how Git LFS handles successful Batch responses.
Successful responses include the following properties:
transfer- String identifier of the transfer adapter that the server prefers. This MUST be one of the giventransferidentifiers from the request. Servers can assume thebasictransfer adapter if none were given. The Git LFS client will use thebasictransfer adapter if thetransferproperty is omitted.objects- An Array of objects to download.oid- String OID of the LFS object.size- Integer byte size of the LFS object. Must be at least zero.authenticated- Optional boolean specifying whether the request for this specific object is authenticated. If omitted or false, Git LFS will attempt to find credentials for this URL.actions- Object containing the next actions for this object. Applicable actions depend on whichoperationis specified in the request. How these properties are interpreted depends on which transfer adapter the client will be using.href- String URL to download the object.header- Optional hash of String HTTP header key/value pairs to apply to the request.expires_in- Whole number of seconds after local client time when transfer will expire. Preferred overexpires_atif both are provided. Maximum of 2147483647, minimum of -2147483647.expires_at- String uppercase RFC 3339-formatted timestamp with second precision for when the given action expires (usually due to a temporary token).
hash_algo- The hash algorithm used to name Git LFS objects for this repository. Optional; defaults tosha256if not specified.
Download operations MUST specify a download action, or an object error if the
object cannot be downloaded for some reason. See “Response Errors” below.
Upload operations can specify an upload and a verify action. The upload
action describes how to upload the object. If the object has a verify action,
the LFS client will hit this URL after a successful upload. Servers can use this
for extra verification, if needed. If a client requests to upload an object that
the server already has, the server should omit the actions property
completely. The client will then assume the server already has it.
// HTTP/1.1 200 Ok
// Content-Type: application/vnd.git-lfs+json
{
"transfer": "basic",
"objects": [
{
"oid": "1111111",
"size": 123,
"authenticated": true,
"actions": {
"download": {
"href": "https://some-download.com",
"header": {
"Key": "value"
},
"expires_at": "2016-11-10T15:29:07Z"
}
}
}
],
"hash_algo": "sha256"
}
If there are problems accessing individual objects, servers should continue to return a 200 status code, and provide per-object errors. Here is an example:
// HTTP/1.1 200 Ok
// Content-Type: application/vnd.git-lfs+json
{
"transfer": "basic",
"objects": [
{
"oid": "1111111",
"size": 123,
"error": {
"code": 404,
"message": "Object does not exist"
}
}
],
"hash_algo": "sha256"
}
LFS object error codes should match HTTP status codes where possible:
- 404 - The object does not exist on the server.
- 409 - The specified hash algorithm disagrees with the server’s acceptable options.
- 410 - The object was removed by the owner.
- 422 - Validation error.
Response Errors
LFS servers can respond with these other HTTP status codes:
- 401 - The authentication credentials are needed, but were not sent. Git LFS will attempt to get the authentication for the request and retry immediately.
- 403 - The user has read, but not write access. Only applicable when
the
operationin the request is “upload.” - 404 - The Repository does not exist for the user.
- 422 - Validation error with one or more of the objects in the request. This means that none of the requested objects to upload are valid.
Error responses will not have an objects property. They will only have:
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 404 Not Found
// Content-Type: application/vnd.git-lfs+json
{
"message": "Not found",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
HTTP 401 responses should include an LFS-Authenticate header to tell the
client what form of authentication it requires. If omitted, Git LFS will assume
Basic Authentication. This mirrors the standard WWW-Authenticate header with
a custom header key so it does not trigger password prompts in browsers.
// HTTP/1.1 401 Unauthorized
// Content-Type: application/vnd.git-lfs+json
// LFS-Authenticate: Basic realm="Git LFS"
{
"message": "Credentials needed",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
The following status codes can optionally be returned from the API, depending on the server implementation.
- 406 - The Accept header needs to be
application/vnd.git-lfs+json. - 413 - The batch API request contained too many objects or the request was otherwise too large.
- 429 - The user has hit a rate limit with the server. Though the API does not specify any rate limits, implementors are encouraged to set some for availability reasons.
- 501 - The server has not implemented the current method. Reserved for future use.
- 507 - The server has insufficient storage capacity to complete the request.
- 509 - The bandwidth limit for the user or repository has been exceeded. The API does not specify any bandwidth limit, but implementors may track usage.
Some server errors may trigger the client to retry requests, such as 500, 502, 503, and 504.
Basic Transfer API
The Basic transfer API is a simple, generic API for directly uploading and downloading LFS objects. Git LFS servers can offload object storage to cloud services like S3, or implement this API natively.
This is the original transfer adapter. All Git LFS clients and servers SHOULD
support it, and default to it if the Batch API request or response
do not specify a transfer property.
Downloads
Downloading an object requires a download action object in the Batch API
response that looks like this:
{
"transfer": "basic",
"objects": [
{
"oid": "1111111",
"size": 123,
"authenticated": true,
"actions": {
"download": {
"href": "https://some-download.com/1111111",
"header": {
"Authorization": "Basic ..."
},
"expires_in": 86400
}
}
}
]
}
The Basic transfer adapter will make a GET request on the href, expecting the
raw bytes returned in the HTTP response.
> GET https://some-download.com/1111111
> Authorization: Basic ...
<
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< Content-Length: 123
<
< {contents}
Uploads
The client uploads objects through individual PUT requests. The URL and headers
are provided by an upload action object.
{
"transfer": "basic",
"objects": [
{
"oid": "1111111",
"size": 123,
"authenticated": true,
"actions": {
"upload": {
"href": "https://some-upload.com/1111111",
"header": {
"Authorization": "Basic ..."
},
"expires_in": 86400
}
}
}
]
}
The Basic transfer adapter will make a PUT request on the href, sending the
raw bytes returned in the HTTP request.
> PUT https://some-upload.com/1111111
> Authorization: Basic ...
> Content-Type: application/octet-stream
> Content-Length: 123
>
> {contents}
>
< HTTP/1.1 200 OK
Verification
The Batch API can optionally return a verify action object in addition to an
upload action object. If given, The Batch API expects a POST to the href
after a successful upload.
{
"transfer": "basic",
"objects": [
{
"oid": "1111111",
"size": 123,
"authenticated": true,
"actions": {
"upload": {
"href": "https://some-upload.com/1111111",
"header": {
"Authorization": "Basic ..."
},
"expires_in": 86400
},
"verify": {
"href": "https://some-verify-callback.com",
"header": {
"Authorization": "Basic ..."
},
"expires_in": 86400
}
}
}
]
}
Git LFS clients send:
oid- The String OID of the Git LFS object.size- The integer size of the Git LFS object, in bytes.
> POST https://some-verify-callback.com
> Accept: application/vnd.git-lfs+json
> Content-Type: application/vnd.git-lfs+json
> Content-Length: 123
>
> {"oid": "{oid}", "size": 10000}
>
< HTTP/1.1 200 OK
The client may also include a charset=utf-8 parameter in the
Content-Type header, which servers should be prepared to accept.
A 200 response means that the object exists on the server.
Git LFS File Locking API
Added: v2.0
The File Locking API is used to create, list, and delete locks, as well as verify that locks are respected in Git pushes. The locking URLs are built by adding a suffix to the LFS Server URL.
Git remote: https://git-server.com/foo/bar
LFS server: https://git-server.com/foo/bar.git/info/lfs
Locks API: https://git-server.com/foo/bar.git/info/lfs/locks
See the Server Discovery doc for more info on how LFS builds the LFS server URL.
All File Locking requests require the following HTTP headers:
Accept: application/vnd.git-lfs+json
Content-Type: application/vnd.git-lfs+json
The client may also include a charset=utf-8 parameter in the
Content-Type header, which servers should be prepared to accept.
See the Authentication doc for more info on how LFS gets authorizes Batch API requests.
Note: This is the first version of the File Locking API, supporting only the simplest use case: single branch locking. The API is designed to be extensible as we experiment with more advanced locking scenarios, as defined in the original proposal.
The Batch API’s ref property docs describe how the ref property can be used to support auth schemes that include the server ref. Locking API implementations should also only use it for authentication, until advanced locking scenarios have been developed.
Create Lock
The client sends the following to create a lock by sending a POST to /locks
(appended to the LFS server url, as described above). Servers should ensure that
users have push access to the repository, and that files are locked exclusively
to one user.
path- String path name of the file that is locked. This should be relative to the root of the repository working directory.ref- Optional object describing the server ref that the locks belong to. Note: Added in v2.4.name- Fully-qualified server refspec.
// POST https://lfs-server.com/locks
// Accept: application/vnd.git-lfs+json
// Content-Type: application/vnd.git-lfs+json
// Authorization: Basic ...
{
"path": "foo/bar.zip",
"ref": {
"name": "refs/heads/my-feature"
}
}
Successful Response
Successful responses return the created lock:
id- String ID of the Lock. Git LFS doesn’t enforce what type of ID is used, as long as it’s returned as a string.path- String path name of the locked file. This should be relative to the root of the repository working directory.locked_at- The timestamp the lock was created, as an uppercase RFC 3339-formatted string with second precision.owner- Optional name of the user that created the Lock. This should be set from the user credentials posted when creating the lock.
// HTTP/1.1 201 Created
// Content-Type: application/vnd.git-lfs+json
{
"lock": {
"id": "some-uuid",
"path": "foo/bar.zip",
"locked_at": "2016-05-17T15:49:06+00:00",
"owner": {
"name": "Jane Doe"
}
}
}
Bad Response: Lock Exists
Lock services should reject lock creations if one already exists for the given path on the current repository.
lock- The existing Lock that clashes with the request.message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 409 Conflict
// Content-Type: application/vnd.git-lfs+json
{
"lock": {
// details of existing lock
},
"message": "already created lock",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Unauthorized Response
Lock servers should require that users have push access to the repository before they can create locks.
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 403 Forbidden
// Content-Type: application/vnd.git-lfs+json
{
"message": "You must have push access to create a lock",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Error Response
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 500 Internal server error
// Content-Type: application/vnd.git-lfs+json
{
"message": "internal server error",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
List Locks
The client can request the current active locks for a repository by sending a
GET to /locks (appended to the LFS server url, as described above). LFS
Servers should ensure that users have at least pull access to the repository.
The properties are sent as URI query values, instead of through a JSON body:
path- Optional string path to match against locks on the server.id- Optional string ID to match against a lock on the server.cursor- The optional string value to continue listing locks. This value should be thenext_cursorfrom a previous request.limit- The integer limit of the number of locks to return. The server should have its own upper and lower bounds on the supported limits.refspec- Optional fully qualified server refspec from which to search for locks.
// GET https://lfs-server.com/locks?path=&id=&cursor=&limit=&refspec=
// Accept: application/vnd.git-lfs+json
// Authorization: Basic ... (if needed)
Successful Response
A successful response will list the matching locks:
locks- Array of matching Lock objects. See the “Create Lock” successful response section to see what Lock properties are possible.next_cursor- Optional string cursor that the server can return if there are more locks matching the given filters. The client will re-do the request, setting the?cursorquery value with thisnext_cursorvalue.
Note: If the server has no locks, it must return an empty locks array.
// HTTP/1.1 200 Ok
// Content-Type: application/vnd.git-lfs+json
{
"locks": [
{
"id": "some-uuid",
"path": "/path/to/file",
"locked_at": "2016-05-17T15:49:06+00:00",
"owner": {
"name": "Jane Doe"
}
}
],
"next_cursor": "optional next ID"
}
Unauthorized Response
Lock servers should require that users have pull access to the repository before they can list locks.
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 403 Forbidden
// Content-Type: application/vnd.git-lfs+json
{
"message": "You must have pull access to list locks",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Error Response
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 500 Internal server error
// Content-Type: application/vnd.git-lfs+json
{
"message": "unable to list locks",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
List Locks for Verification
The client can use the Lock Verification endpoint to check for active locks that can affect a Git push. For a caller, this endpoint is very similar to the “List Locks” endpoint above, except:
- Verification requires a
POSTrequest. - The
cursor,refandlimitvalues are sent as properties in the json request body. - The response includes locks partitioned into
oursandtheirsproperties.
LFS Servers should ensure that users have push access to the repository.
Clients send the following to list locks for verification by sending a POST
to /locks/verify (appended to the LFS server url, as described above):
ref- Optional object describing the server ref that the locks belong to. Note: Added in v2.4.name- Fully-qualified server refspec.
cursor- Optional cursor to allow pagination. Servers can determine how cursors are formatted based on how they are stored internally.limit- Optional limit to how many locks to return.
// POST https://lfs-server.com/locks/verify
// Accept: application/vnd.git-lfs+json
// Content-Type: application/vnd.git-lfs+json
// Authorization: Basic ...
{
"cursor": "optional cursor",
"limit": 100, // also optional
"ref": {
"name": "refs/heads/my-feature"
}
}
Note: As more advanced locking workflows are implemented, more details will likely be added to this request body in future iterations.
Successful Response
A successful response will list the relevant locks:
ours- Array of Lock objects currently owned by the authenticated user. modify.theirs- Array of Lock objects currently owned by other users.next_cursor- Optional string cursor that the server can return if there are more locks matching the given filters. The client will re-do the request, setting thecursorproperty with thisnext_cursorvalue.
If a Git push updates any files matching any of “our” locks, Git LFS will list them in the push output, in case the user will want to unlock them after the push. However, any updated files matching one of “their” locks will halt the push. At this point, it is up to the user to resolve the lock conflict with their team.
Note: If the server has no locks, it must return an empty array in the ours or
theirs properties.
// HTTP/1.1 200 Ok
// Content-Type: application/vnd.git-lfs+json
{
"ours": [
{
"id": "some-uuid",
"path": "/path/to/file",
"locked_at": "2016-05-17T15:49:06+00:00",
"owner": {
"name": "Jane Doe"
}
}
],
"theirs": [],
"next_cursor": "optional next ID"
}
Not Found Response
By default, an LFS server that doesn’t implement any locking endpoints should return 404. This response will not halt any Git pushes.
Any 404 will do, but Git LFS will show a better error message with a json response.
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 404 Not found
// Content-Type: application/vnd.git-lfs+json
{
"message": "Not found",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Unauthorized Response
Lock servers should require that users have push access to the repository before they can get a list of locks to verify a Git push.
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 403 Forbidden
// Content-Type: application/vnd.git-lfs+json
{
"message": "You must have push access to verify locks",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Error Response
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 500 Internal server error
// Content-Type: application/vnd.git-lfs+json
{
"message": "unable to list locks",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Delete Lock
The client can delete a lock, given its ID, by sending a POST to
/locks/:id/unlock (appended to the LFS server url, as described above). LFS
servers should ensure that callers have push access to the repository. They
should also prevent a user from deleting another user’s lock, unless the force
property is given.
Properties:
force- Optional boolean specifying that the user is deleting another user’s lock.ref- Optional object describing the server ref that the locks belong to. Note: Added in v2.4.name- Fully-qualified server refspec.
// POST https://lfs-server.com/locks/:id/unlock
// Accept: application/vnd.git-lfs+json
// Content-Type: application/vnd.git-lfs+json
// Authorization: Basic ...
{
"force": true,
"ref": {
"name": "refs/heads/my-feature"
}
}
Successful Response
Successful deletions return the deleted lock. See the “Create Lock” successful response section to see what Lock properties are possible.
// HTTP/1.1 200 Ok
// Content-Type: application/vnd.git-lfs+json
{
"lock": {
"id": "some-uuid",
"path": "/path/to/file",
"locked_at": "2016-05-17T15:49:06+00:00",
"owner": {
"name": "Jane Doe"
}
}
}
Unauthorized Response
Lock servers should require that users have push access to the repository before
they can delete locks. Also, if the force parameter is omitted, or false,
the user should only be allowed to delete locks that they created.
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 403 Forbidden
// Content-Type: application/vnd.git-lfs+json
{
"message": "You must have push access to delete locks",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
Error response
message- String error message.request_id- Optional String unique identifier for the request. Useful for debugging.documentation_url- Optional String to give the user a place to report errors.
// HTTP/1.1 500 Internal server error
// Content-Type: application/vnd.git-lfs+json
{
"message": "unable to delete lock",
"documentation_url": "https://lfs-server.com/docs/errors",
"request_id": "123"
}
git-lfs
Name
git-lfs — Git LFS — large file storage for git
Synopsis
git-lfs [COMMAND]
Description
Git LFS — large file storage for git
Git LFS is a system for managing and versioning large files in association with a Git repository. Instead of storing the large files within the Git repository as blobs, Git LFS stores special “pointer files” in the repository, while storing the actual file contents on a Git LFS server. The contents of the large file are downloaded automatically when needed, for example when a Git branch containing the large file is checked out.
Git LFS works by using a “smudge” filter to look up the large file contents based on the pointer file, and a “clean” filter to create a new version of the pointer file when the large file’s contents change. It also uses a pre-push hook to upload the large file contents to the Git LFS server whenever a commit containing a new large file version is about to be pushed to the corresponding Git server.
Options
Flags
-V,--versionPrint the version banner and exit
Subcommands
clean— Git clean filter that converts large files to pointerssmudge— Git smudge filter that converts pointer in blobs to the actual contentinstall— Install Git LFS configurationuninstall— Remove Git LFS configurationtrack— View or add Git LFS paths to Git attributesuntrack— Remove Git LFS paths from Git attributesfilter-process— Git filter process that converts between pointer and actual contentfetch— Download all Git LFS files for a given refpull— Download all Git LFS files for current ref and checkoutpush— Push queued large files to the Git LFS endpointclone— Efficiently clone a LFS-enabled repositorypost-checkout— Git post-checkout hook implementationpost-commit— Git post-commit hook implementationpost-merge— Git post-merge hook implementationpre-push— Git pre-push hook implementationversion— Print the git-lfs version banner and exitpointer— Build, compare, and check pointersenv— Display the Git LFS environmentext— List the configured LFS pointer extensionsupdate— Update Git hooksmigrate— Migrate history to or from Git LFScheckout— Populate working copy with real content from Git LFS filesprune— Delete old LFS files from local storagefsck— Check Git LFS files for consistencystatus— Show the status of Git LFS files in the working treelock— Set a file as “locked” on the Git LFS serverlocks— Lists currently locked files from the Git LFS serverunlock— Remove “locked” setting for a file on the Git LFS serverls-files— Show information about Git LFS files in the index and working treelogs— Show errors logged by Git LFSmerge-driver— Merge driver for LFS-tracked files
Examples
To get started with Git LFS, the following commands can be used.
-
Setup Git LFS on your system. You only have to do this once per user account:
git lfs install -
Choose the type of files you want to track, for examples all ISO images, with git-lfs-track(1):
git lfs track "*.iso" -
The above stores this information in gitattributes(5) files, so that file needs to be added to the repository:
git add .gitattributes -
Commit, push and work with the files normally:
git add file.iso git commit -m "Add disk image" git push
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-checkout
Name
git-lfs-checkout — Populate working copy with real content from Git LFS files
Synopsis
git-lfs-checkout [OPTIONS] [PATHS]...
Description
Populate working copy with real content from Git LFS files.
Try to ensure that the working copy contains file content for Git LFS objects for the current ref, if the object data is available. Does not download any content; see git-lfs-fetch(1) for that.
Checkout scans the current ref for all LFS objects that would be required, then where a file is either missing in the working copy, or contains placeholder pointer content with the same SHA, the real file content is written, provided we have it in the local store. Modified files are never overwritten.
One or more may be provided as arguments to restrict the set of files that are updated. Glob patterns are matched as per the format described in gitignore(5).
When used with --to and the working tree is in a conflicted state due to a merge, this option checks out one of the three stages a conflicting Git LFS object into a separate file (which can be outside of the work tree). This can make using diff tools to inspect and resolve merges easier. A single Git LFS object’s file path must be provided in PATHS. If FILE already exists, whether as a regular file, symbolic link, or directory, it will be removed and replaced, unless it is a non-empty directory or otherwise cannot be deleted.
If the installed Git version is at least 2.42.0, this command will by default check out Git LFS objects for files only if they are present in the Git index and if they match a Git LFS filter attribute from a .gitattributes file that is present in either the index or the current working tree (or, as is always the case, if they match a Git LFS filter attribute in a local gitattributes file such as $GIT_DIR/info/attributes). These constraints do not apply with prior versions of Git.
In a repository with a partial clone or sparse checkout, it is therefore advisable to check out all .gitattributes files from HEAD before using this command, if Git v2.42.0 or later is installed. Alternatively, the GIT_ATTR_SOURCE environment variable may be set to HEAD, which will cause Git to only read attributes from .gitattributes files in HEAD and ignore those in the index or working tree.
In a bare repository, this command prints an informational message and exits without modifying anything. In a future version, it may exit with an error.
Options
Arguments
-
<PATHS>Paths to check out.When empty, everything in HEAD’s tree is checked out. In conflict mode (
--to <path>together with one of--base,--ours, or--theirs), exactly one path is required.
Flags
-
--baseCheck out the merge base of the specified file -
--oursCheck out our side (that of the current branch) of the conflict for the specified file -
--theirsCheck out their side (that of the other branch) of the conflict for the specified file -
--to<FILE>If the working tree is in a conflicted state, check out the portion of the conflict specified by--base,--ours, or--theirsto the given path. Exactly one of these options is required
Examples
Checkout all files that are missing or placeholders:
git lfs checkout
Checkout a specific couple of files:
git lfs checkout path/to/file1.png path/to/file2.png
Checkout a path with a merge conflict into separate files:
# Attempt merge with a branch that has a merge conflict
$ git merge conflicting-branch
CONFLICT (content): Merge conflict in path/to/conflicting/file.dat
# Checkout versions of the conflicting file into temp files
$ git lfs checkout --to ours.dat --ours path/to/conflicting/file.dat
$ git lfs checkout --to theirs.dat --theirs path/to/conflicting/file.dat
# Compare conflicting versions in ours.dat and theirs.dat,
# then resolve conflict (e.g., by choosing one version over
# the other, or creating a new version)
# Cleanup and continue with merge
$ rm ours.dat theirs.dat
$ git add path/to/conflicting/file.dat
$ git merge --continue
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-clone
Name
git-lfs-clone — Efficiently clone a LFS-enabled repository
Synopsis
git-lfs-clone [ARGS]...
Description
Efficiently clone a LFS-enabled repository
Clone an LFS-enabled Git repository by disabling LFS during the git clone, then running git lfs pull directly afterwards. Also installs the repo-level hooks (.git/hooks) that LFS requires to operate; if --separate-git-dir is given to git clone, the hooks are installed there.
Historically faster than a regular git clone because that would download LFS content via the smudge filter one file at a time. Modern git clone parallelizes the smudge filter, so this command no longer offers a meaningful speedup over plain git clone. You should prefer plain git clone.
In addition to the options accepted by git clone, the LFS-only flags --include / -I <paths>, --exclude / -X <paths>, and --skip-repo (skip installing the repo-level hooks) are accepted — see git-lfs-fetch(1) for the include/exclude semantics. They’re parsed from the trailing argument list rather than declared as clap flags, so they don’t appear in this command’s --help.
Options
Arguments
<ARGS>git clonearguments plus the LFS pass-through flags (-I/--include,-X/--exclude,--skip-repo). The repository URL is required; an optional target directory follows
See also
git-clone(1), git-lfs-pull(1), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-env
Name
git-lfs-env — Display the Git LFS environment
Synopsis
git-lfs-env
Description
Display the Git LFS environment
Display the current Git LFS environment: version, endpoints, on-disk paths, and the three filter.lfs.* config values.
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-ext
Name
git-lfs-ext — List the configured LFS pointer extensions
Synopsis
git-lfs-ext [COMMAND]
Description
List the configured LFS pointer extensions
Print each lfs.extension.<name>.* entry resolved to its final configuration in priority order. Extensions chain external clean / smudge programs around each LFS object — see git-lfs-config(5) for how to configure them.
With no arguments, prints every configured extension. With list <name>..., prints only the named extensions (one block per name, in argument order).
Options
Subcommands
list— List configured LFS pointer extensions, optionally filtered by name
Examples
List details for all extensions:
git lfs ext
or equivalently:
git lfs ext list
List details for the specified extensions:
git lfs ext list foo bar
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-fetch
Name
git-lfs-fetch — Download all Git LFS files for a given ref
Synopsis
git-lfs-fetch [OPTIONS] [ARGS]...
Description
Download all Git LFS files for a given ref
Download Git LFS objects at the given refs from the specified remote. See DEFAULT REMOTE and DEFAULT REFS for what happens if you don’t specify.
This does not update the working copy; use git-lfs-pull(1) to download and replace pointer text with object content, or git-lfs-checkout(1) to materialize already-downloaded objects.
Options
Arguments
<ARGS>Optional remote name followed by refs. The first positional argument is treated as a remote name when it resolves; any following arguments are refs to fetch
Flags
-
-I,--include<INCLUDE>Specifylfs.fetchincludejust for this invocation; see INCLUDE AND EXCLUDE -
-X,--exclude<EXCLUDE>Specifylfs.fetchexcludejust for this invocation; see INCLUDE AND EXCLUDE -
-a,--allDownload all objects that are referenced by any commit reachable from the refs provided as arguments.If no refs are provided, then all refs are fetched. This is primarily for backup and migration purposes. Cannot be combined with
--include/--exclude. Ignores any globally configured include and exclude paths to ensure that all objects are downloaded. -
--stdinRead a list of newline-delimited refs from standard input instead of the command line -
-p,--prunePrune old and unreferenced objects after fetching, equivalent to runninggit lfs pruneafterwards. See git-lfs-prune(1) for more details -
--refetchAlso fetch objects that are already present locally.Useful for recovery from a corrupt local store.
-
-d,--dry-runPrint what would be fetched, without actually fetching anything -
-r,--recentAlso fetch recently-touched refs and the recent pre-images on each.Walk every ref under
refs/heads/(and, by default, every remote-tracking ref) whose tip commit lies withinlfs.fetchrecentrefsdaysof today, and on each of those refs download the pre-image of every LFS file modified withinlfs.fetchrecentcommitsdays. Combine with the named refs’ HEAD-state fetch. The same behaviour fires automatically iflfs.fetchrecentalwaysis set. -
-j,--jsonWrite the details of all object transfer requests as JSON to standard output.Intended for interoperation with external tools. When
--dry-runis also specified, writes the details of the transfers that would occur if the objects were fetched.
Include and exclude
You can configure Git LFS to only fetch objects to satisfy references in certain paths of the repo, and/or to exclude certain paths of the repo, to reduce the time you spend downloading things you do not use.
In your Git configuration or in a .lfsconfig file, you may set
either or both of lfs.fetchinclude and lfs.fetchexclude to
comma-separated lists of paths. If lfs.fetchinclude is defined, Git
LFS objects will only be fetched if their path matches one in that
list, and if lfs.fetchexclude is defined, Git LFS objects will only
be fetched if their path does not match one in that list. Paths are
matched using wildcard matching as per gitignore(5).
Note that using the command-line options -I and -X override the
respective configuration settings. Setting either option to an empty
string clears the value.
Examples:
git config lfs.fetchinclude "textures,images/foo*"- This will only fetch objects referenced in paths in the
texturesfolder, and files calledfoo*in theimagesfolder. git config lfs.fetchinclude "*.jpg,*.png,*.tga"- Only fetch JPG/PNG/TGA files, wherever they are in the repository.
git config lfs.fetchexclude "media/reallybigfiles"- Don’t fetch any LFS objects referenced in the folder
media/reallybigfiles, but fetch everything else. git config lfs.fetchinclude "media"
git config lfs.fetchexclude "media/excessive"- Only fetch LFS objects in the
mediafolder, but exclude those in one of its subfolders.
Default remote
Without arguments, fetch downloads from the default remote. The default
remote is the same as for git fetch, i.e. based on the remote branch
you’re tracking first, or origin otherwise.
Default refs
If no refs are given as arguments, the currently checked out ref is
used. With --recent (or lfs.fetchrecentalways=true), recently-touched
refs and commits are also fetched — see RECENT CHANGES.
Recent changes
With --recent (or lfs.fetchrecentalways=true), fetch downloads objects from recently-active refs and commits in addition to the ones the named refs ask for. The idea is to pre-populate the cache so a later checkout or diff of “what we were working on last week” doesn’t trigger another download round-trip.
What counts as ‘recent’ is controlled by these gitconfig keys:
lfs.fetchrecentrefsdays: include branches whose tip commit is within this many days of now. Only local refs are scanned unlesslfs.fetchrecentremoterefsis also set. Default 7.lfs.fetchrecentremoterefs: also scan the remote-tracking refs of the remote being fetched. Useful for picking up branches you might check out later without first creating a tracking local ref. Default true.lfs.fetchrecentcommitsdays: in addition to fetching the tip state of each recent ref, also fetch any LFS object referenced by commits within this many days of that ref’s tip. Default 0 (tip only).lfs.fetchrecentalways: when true, always behave as if--recentwas passed. Default false.
Examples
Fetch the LFS objects for the current ref from the default remote:
git lfs fetch
Fetch the LFS objects for the current ref AND recent changes from the default remote (see RECENT CHANGES):
git lfs fetch --recent
Fetch the LFS objects for the current ref from a secondary remote
upstream:
git lfs fetch upstream
Fetch all the LFS objects from the default remote that are referenced
by any commit in the main and develop branches:
git lfs fetch --all origin main develop
Fetch the LFS objects for a branch from origin:
git lfs fetch origin mybranch
Fetch the LFS objects for two branches and a commit from origin:
git lfs fetch origin main mybranch e445b45c1c9c6282614f201b62778e4c0688b5c8
See also
git-lfs-checkout(1), git-lfs-pull(1), git-lfs-prune(1), gitconfig(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-fsck
Name
git-lfs-fsck — Check Git LFS files for consistency
Synopsis
git-lfs-fsck [OPTIONS] [REFSPEC]
Description
Check Git LFS files for consistency
Check all Git LFS files in the current HEAD for consistency. Corrupted files are moved to .git/lfs/bad.
A single committish may be given to inspect that commit instead of HEAD. The <a>..<b> range form from upstream is not yet supported — only a single ref is accepted. With no argument, HEAD is examined.
The default is to perform all checks. lfs.fetchexclude is also not yet honored on this command; objects whose paths match the exclude list will still be checked.
Options
Arguments
<REFSPEC>Ref to scan. Defaults to HEAD
Flags
-
--objectsCheck that each object in HEAD matches its expected hash and that each object exists on disk -
--pointersCheck that each pointer is canonical and that each file which should be stored as a Git LFS file is so stored -
-d,--dry-runPerform checks, but do not move any corrupted files to.git/lfs/bad
See also
git-lfs-ls-files(1), git-lfs-status(1), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-install
Name
git-lfs-install — Install Git LFS configuration
Synopsis
git-lfs-install [OPTIONS]
Description
Install Git LFS configuration
Set up the lfs smudge and clean filters under the name lfs in the global Git config, and (when run from inside a repository) install a pre-push hook to run git-lfs-pre-push(1). If core.hooksPath is configured in any Git configuration (supported on Git v2.9.0 or later), the pre-push hook is installed to that directory instead.
Without any options, only sets up the lfs smudge and clean filters if they are not already set.
Options
Flags
-
-f,--forceSet thelfssmudge and clean filters, overwriting existing values -
-l,--localSet thelfssmudge and clean filters in the local repository’s git config, instead of the global git config (~/.gitconfig) -
-w,--worktreeSet thelfssmudge and clean filters in the current working tree’s git config, instead of the global git config (~/.gitconfig) or local repository’s git config ($GIT_DIR/config).If multiple working trees are in use, the Git config extension
worktreeConfigmust be enabled to use this option. If only one working tree is in use,--worktreehas the same effect as--local. Available only on Git v2.20.0 or later. -
--systemSet thelfssmudge and clean filters in the system git config, e.g./etc/gitconfiginstead of the global git config (~/.gitconfig) -
--file<PATH>Set thelfssmudge and clean filters in the Git configuration file specified by<PATH> -
-s,--skip-smudgeSkip automatic downloading of objects on clone or pull.Requires a manual
git lfs pullevery time a new commit is checked out on the repository. -
--skip-repoSkip installation of hooks into the local repository.Use if you want to install the LFS filters but not make changes to the hooks. Valid alongside
--local,--worktree,--system, or--file.
See also
git-lfs-uninstall(1), git-worktree(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-lock
Name
git-lfs-lock — Set a file as “locked” on the Git LFS server
Synopsis
git-lfs-lock [OPTIONS] [PATHS]...
Description
Set a file as “locked” on the Git LFS server
Sets the given file path as “locked” against the Git LFS server, with the intention of blocking attempts by other users to update the given path. Locking a file requires the file to exist in the working copy.
Once locked, LFS will verify that Git pushes do not modify files locked by other users. See the description of the lfs.<url>.locksverify config key in git-lfs-config(5) for details.
Options
Arguments
<PATHS>Paths to lock. Repo-relative or absolute; must resolve inside the working tree. Upstream’s CLI accepts a single path; ours accepts multiple (additive extension)
Flags
-
-r,--remote<REMOTE>Specify the Git LFS server to use. Ignored if thelfs.urlconfig key is set -
-j,--jsonWrite lock info as JSON to standard output if the command exits successfully.Intended for interoperation with external tools. If the command returns with a non-zero exit code, plain text messages are sent to standard error.
-
--ref<REFSPEC>Refspec to associate the lock with (extension over upstream).Defaults to the current branch’s tracked upstream (
branch.<current>.merge) or the current branch’s full ref (refs/heads/<branch>).
See also
git-lfs-unlock(1), git-lfs-locks(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-locks
Name
git-lfs-locks — Lists currently locked files from the Git LFS server
Synopsis
git-lfs-locks [OPTIONS]
Description
Lists currently locked files from the Git LFS server
Lists current locks from the Git LFS server. Without filters, all locks visible to the configured remote are returned.
Options
Flags
-
-r,--remote<REMOTE>Specify the Git LFS server to use. Ignored if thelfs.urlconfig key is set -
-i,--id<ID>Specify a lock by its ID. Returns a single result -
-p,--path<PATH>Specify a lock by its path. Returns a single result -
--localList only our own locks which are cached locally. Skips a remote call.Useful when offline or to confirm what
git lfs lockrecorded locally. Combine with--path/--id/--limitto filter;--verifyis rejected. -
--verifyVerify the lock owner on the server and mark our own locks withO.Own locks are held by us and the corresponding files can be updated for the next push. All other locks are held by someone else. Contrary to
--local, this also detects locks held by us despite no local lock information being available (e.g. because the file had been locked from a different clone) and detects “broken” locks (e.g. someone else forcibly unlocked our files). -
-l,--limit<LIMIT>Maximum number of results to return -
-j,--jsonWrite lock info as JSON to standard output if the command exits successfully.Intended for interoperation with external tools. If the command returns with a non-zero exit code, plain text messages are sent to standard error.
-
--ref<REFSPEC>Refspec to filter locks by (extension over upstream).Defaults to the current branch’s tracked upstream — same auto-resolution as
git lfs lock.
See also
git-lfs-lock(1), git-lfs-unlock(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-ls-files
Name
git-lfs-ls-files — Show information about Git LFS files in the index and working tree
Synopsis
git-lfs-ls-files [OPTIONS] [REFSPEC]
Description
Show information about Git LFS files in the index and working tree
Display paths of Git LFS files that are found in the tree at the given reference. If no reference is given, scan the currently checked-out branch.
An asterisk (*) after the OID indicates a full object, a minus (-) indicates an LFS pointer.
Note: upstream’s --include / --exclude path filters aren’t yet supported. The two-references form (git lfs ls-files <a> <b>, to show files modified between two refs) is also not yet supported.
Options
Arguments
<REFSPEC>Ref to list. Defaults to HEAD
Flags
-
-l,--longShow the entire 64-character OID, instead of just the first 10 -
-s,--sizeShow the size of the LFS object in parentheses at the end of each line -
-n,--name-onlyShow only the LFS-tracked file names -
-a,--allInspect the full history of the repository, not the current HEAD (or other provided reference).Includes previous versions of LFS objects that are no longer found in the current tree.
-
-d,--debugShow as much information as possible about an LFS file.Intended for manual inspection; the exact format may change at any time.
-
--deletedInclude LFS pointers reachable from history but no longer present in the current tree -
-j,--jsonWrite Git LFS file information as JSON to standard output if the command exits successfully.Intended for interoperation with external tools. If
--debugis also provided, that option takes precedence. If any of--long,--size, or--name-onlyare provided, those options will have no effect.
See also
git-lfs-status(1), git-lfs-config(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-migrate
Name
git-lfs-migrate — Migrate history to or from Git LFS
Synopsis
git-lfs-migrate <COMMAND>
Description
Migrate history to or from Git LFS
Convert files in a Git repository to or from Git LFS pointers, or summarize Git file sizes by file type. The import mode converts Git files (i.e. blobs) to Git LFS, the export mode does the reverse, and the info mode provides an informational summary useful for deciding which files to import or export.
In all modes, by default git lfs migrate operates only on the currently checked-out branch, and only on files added in commits which do not exist on any remote. Multiple options are available to override these defaults — see INCLUDE AND EXCLUDE REFERENCES.
When converting files to or from Git LFS, this command only changes your local repository and working copy, never any remotes. import and export are generally DESTRUCTIVE — they rewrite Git history, changing commits and generating new commit SHAs. (The exception is the --no-rewrite import sub-mode.) Always commit or stash any uncommitted work first, validate the result before pushing, and force-push the new history once you’re satisfied.
For info and import, all file types are considered by default. In import you’ll usually want filename patterns or --fixup; export requires at least one --include pattern. See INCLUDE AND EXCLUDE.
git lfs migrate will examine, create, and modify .gitattributes files as necessary. They are always assigned the default read/write permissions mode; symbolic links with that name halt the migration.
Options
Subcommands
import— Convert Git objects to Git LFS pointersexport— Convert Git LFS pointers to Git objectsinfo— Show information about repository size
Include and exclude
You can have git lfs migrate convert only files whose pathspec
matches the --include glob patterns and does not match the
--exclude glob patterns, either to reduce total migration time or
to migrate part of your repo. Multiple patterns may be given using
commas as delimiters.
Pattern matching is functionally equivalent to the
.gitattributes format. In addition to simple file extension
matches (e.g. *.gif), patterns may also specify directory paths,
in which case the path/** form may be used to match recursively.
Note that this form of pattern matching for --include /
--exclude is unique to git lfs migrate. Other commands which
also take these options (such as git lfs ls-files) use the
gitignore(5) form of pattern matching instead.
Include and exclude references
You can have git lfs migrate convert only files added in commits
reachable from certain references — defined with --include-ref —
and ignore files in commits reachable from references defined with
--exclude-ref.
For example, given:
D---E---F
/ \
A---B------C refs/heads/my-feature
\ \
\ refs/heads/main
\
refs/remotes/origin/main
The commits reachable by each ref:
refs/heads/main: C, B, A
refs/heads/my-feature: F, E, D, B, A
refs/remotes/origin/main: A
The following options would include commits F, E, D, C, and B but exclude commit A:
--include-ref=refs/heads/my-feature
--include-ref=refs/heads/main
--exclude-ref=refs/remotes/origin/main
The presence of --everything indicates that all commits reachable
from all local and remote references should be migrated. Note that
the remote refs themselves are never updated by the migration.
Examples
List the file types taking up the most space in your repository’s unpushed commits:
git lfs migrate info
Convert specific file types in unpushed commits to LFS:
git lfs migrate import --include="*.mp3,*.psd"
Check for large files and existing LFS objects across every branch:
git lfs migrate info --everything
Convert all zip files in every local branch to LFS:
git lfs migrate import --everything --include="*.zip"
Convert all files over 100K in every local branch:
git lfs migrate import --everything --above=100Kb
Migrate to Git LFS in a single new commit (no history rewrite):
git lfs track "*.zip" "*.mp3" "*.psd"
git add .gitattributes
git commit -m "add Git LFS attributes"
git lfs migrate import --no-rewrite --yes test.zip audios/*.mp3 images/*.psd
Convert all zip Git LFS objects back to regular Git blobs:
git lfs migrate export --include-ref=main --include="*.zip"
After any history-rewriting migration, force-push the rewritten branches to your remotes — this alters Git history on your remotes and should be done with care.
See also
git-lfs-checkout(1), git-lfs-ls-files(1), git-lfs-track(1), git-lfs-untrack(1), gitattributes(5), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-migrate-import
Name
git-lfs-migrate-import — Convert Git objects to Git LFS pointers
Synopsis
git-lfs-migrate-import [OPTIONS] [ARGS]...
Description
Convert Git objects to Git LFS pointers
Migrate objects present in the Git history to pointer files tracked and stored with Git LFS. Adds entries for the converted file types to .gitattributes, creating those files if they don’t exist — as if git lfs track had been run at the points in history where each type first appears.
With --fixup, examine existing .gitattributes files and convert only Git objects that should be tracked by Git LFS according to those rules but aren’t yet.
With --no-rewrite, migrate objects to pointers in a single new commit on top of HEAD without rewriting history. The base migrate options (--include-ref, --everything, etc.) are ignored in this sub-mode, and the positional argument list changes from branches to a list of files. Files must be tracked by patterns already in .gitattributes.
Options
Arguments
<ARGS>Branches to rewrite (default: the currently checked-out branch). With--no-rewrite, instead a list of working-tree files to convert. References prefixed with^are excluded
Flags
-
-I,--include<INCLUDE>Convert paths matching this glob (repeatable, comma-delimited). Required unless--aboveis set or--no-rewriteis given -
-X,--exclude<EXCLUDE>Exclude paths matching this glob (repeatable, comma-delimited) -
--include-ref<INCLUDE_REF>Restrict the rewrite to commits reachable from these refs. Repeatable -
--exclude-ref<EXCLUDE_REF>Exclude commits reachable from these refs. Repeatable -
--everythingConsider all commits reachable from any local or remote ref.Only local refs are updated even with
--everything; remote refs stay synchronized with their remote. -
--above<ABOVE>Only migrate files whose individual filesize is above the given size (e.g.1b,20 MB,3 TiB).Cannot be used with
--include,--exclude, or--fixup. -
--no-rewriteMigrate objects in a new commit on top of HEAD without rewriting Git history.Switches to a different argument list (positional args become files, not branches) and ignores the core
migrateoptions (--include-ref,--everything, etc.). -
-m,--message<MESSAGE>Commit message for the--no-rewritecommit.If omitted, a message is generated from the file arguments.
-
--fixupInfer--includeand--excludefilters per-commit from the repository’s.gitattributesfiles.Imports filepaths that should be tracked by Git LFS but aren’t yet pointers. Incompatible with explicitly given
--include/--excludefilters. -
--object-map<OBJECT_MAP>Write a CSV of<OLD-SHA>,<NEW-SHA>for every rewritten commit to the named file -
--verbosePrint the commit OID and filename of migrated files to standard output -
--remote<REMOTE>Remote to consult when fetching missing LFS objects (defaultorigin) -
--skip-fetchDon’t refresh the known set of remote references before determining the set of “un-pushed” commits to migrate.Has no effect when combined with
--include-refor--exclude-ref. -
--yesAssume a yes answer to any prompts, permitting noninteractive use.Currently we don’t prompt for any reason, so this is accepted as a no-op for upstream parity.
Examples
Convert specific file types in unpushed commits to LFS:
git lfs migrate import --include="*.mp3,*.psd"
Convert all zip files across every local branch:
git lfs migrate import --everything --include="*.zip"
Convert every file over 100K in every local branch:
git lfs migrate import --everything --above=100Kb
Repair already-committed files that should be LFS pointers according to .gitattributes but aren’t (e.g. committed while git lfs install wasn’t active):
git lfs migrate import --fixup
Migrate to Git LFS in a single new commit on top of HEAD without rewriting history:
git lfs track "*.zip" "*.mp3" "*.psd"
git add .gitattributes
git commit -m "add Git LFS attributes"
git lfs migrate import --no-rewrite test.zip audios/*.mp3 images/*.psd
After any history-rewriting migration, force-push the rewritten branches — this alters Git history on your remotes and should be done with care.
See also
git-lfs-migrate(1), git-lfs-migrate-export(1), git-lfs-migrate-info(1), git-lfs-track(1), gitattributes(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-migrate-export
Name
git-lfs-migrate-export — Convert Git LFS pointers to Git objects
Synopsis
git-lfs-migrate-export [OPTIONS] [BRANCHES]...
Description
Convert Git LFS pointers to Git objects
Migrate Git LFS pointer files present in the Git history out of Git LFS, converting them back into their corresponding object files. Files matching the --include patterns are removed from Git LFS; files matching --exclude retain their LFS status. Modifies .gitattributes to set/unset the relevant filepath patterns.
At least one --include pattern is required. Objects not present in the local LFS store are downloaded from the --remote (defaults to origin). Pointers whose objects can’t be fetched are left as-is.
Options
Arguments
<BRANCHES>Branches to rewrite (default: the currently checked-out branch). References prefixed with^are excluded
Flags
-
-I,--include<INCLUDE>Convert pointers at paths matching this glob (repeatable, comma-delimited). Required — at least one must be given -
-X,--exclude<EXCLUDE>Don’t convert pointers at paths matching this glob (repeatable, comma-delimited) -
--include-ref<INCLUDE_REF>Restrict the rewrite to commits reachable from these refs. Repeatable -
--exclude-ref<EXCLUDE_REF>Exclude commits reachable from these refs. Repeatable -
--everythingConsider all commits reachable from any local or remote ref.Only local refs are updated even with
--everything; remote refs stay synchronized with their remote. -
--object-map<OBJECT_MAP>Write a CSV of<OLD-SHA>,<NEW-SHA>for every rewritten commit to the named file.Useful as input to
git filter-repoor other downstream tools. -
--verbosePrint the commit OID and filename of migrated files to standard output -
--remote<REMOTE>Download LFS objects from this remote during the export. Defaults toorigin -
--skip-fetchDon’t refresh the known set of remote references before the rewrite -
--yesAssume a yes answer to any prompts, permitting noninteractive use.Currently we don’t prompt for any reason, so this is accepted as a no-op for upstream parity.
Examples
Convert all zip Git LFS pointers on main back to regular Git blobs:
git lfs migrate export --include-ref=main --include="*.zip"
Pointers whose objects aren’t in the local store are downloaded from the --remote (defaults to origin); pointers that can’t be downloaded are left as-is.
After exporting, the rewritten branches need to be force-pushed — this rewrites history on the remote.
See also
git-lfs-migrate(1), git-lfs-migrate-import(1), git-lfs-migrate-info(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-migrate-info
Name
git-lfs-migrate-info — Show information about repository size
Synopsis
git-lfs-migrate-info [OPTIONS] [BRANCHES]...
Description
Show information about repository size
Summarize the sizes of file objects present in the Git history, grouped by filename extension. Read-only — no objects or history change.
Existing Git LFS pointers are followed by default (the size of the referenced objects is totaled in a separate “LFS Objects” line). Use --pointers=ignore to skip pointers entirely, or --pointers=no-follow to count the pointer-text size as if the pointers were regular files (the older Git LFS behavior).
Options
Arguments
<BRANCHES>Branches to scan (default: the currently checked-out branch). References prefixed with^are excluded
Flags
-
-I,--include<INCLUDE>Only include paths matching this glob (repeatable, comma-delimited) -
-X,--exclude<EXCLUDE>Exclude paths matching this glob (repeatable, comma-delimited) -
--include-ref<INCLUDE_REF>Restrict the scan to commits reachable from these refs. Repeatable -
--exclude-ref<EXCLUDE_REF>Exclude commits reachable from these refs. Repeatable -
--everythingConsider all commits reachable from any local or remote ref -
--above<ABOVE>Only count files whose individual filesize is above the given size (e.g.1b,20 MB,3 TiB).File-extension groups whose largest file is below
--abovedon’t appear in the output. -
--top<TOP>Display the top N entries, ordered by total file count.Default 5. When existing Git LFS objects are found, an extra “LFS Objects” line is output in addition to the top N entries (unless
--pointerschanges this). -
--pointers<POINTERS>How to handle existing LFS pointer blobs.follow(default): summarize referenced objects in a separate “LFS Objects” line.ignore: skip pointers entirely.no-follow: count pointer-text size as if pointers were regular files (the older Git LFS behavior). When--fixupis given, defaults toignore. -
--unit<UNIT>Format byte quantities in this unit.Valid units:
b, kib, mib, gib, tib, pib(IEC) orb, kb, mb, gb, tb, pb(SI). Auto-scaled when omitted. -
--fixupInfer--includeand--excludefilters per-commit from the repository’s.gitattributesfiles.Counts filepaths that should be tracked by Git LFS but aren’t yet pointers. Incompatible with explicit
--include/--excludefilters and with--pointerssettings other thanignore. Implies--pointers=ignoreif not set. -
--skip-fetchDon’t refresh the known set of remote references before the scan -
--remote<REMOTE>Remote to consult (currently a no-op; reserved for the auto-fetch path)
Examples
List the file types taking up the most space in unpushed commits:
git lfs migrate info
Check large files and existing LFS objects across every branch (local + remote):
git lfs migrate info --everything
Report files that should be tracked by Git LFS according to the repository’s .gitattributes but aren’t yet pointers — the candidate set for git lfs migrate import --fixup:
git lfs migrate info --fixup
See also
git-lfs-migrate(1), git-lfs-migrate-import(1), git-lfs-migrate-export(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-prune
Name
git-lfs-prune — Delete old LFS files from local storage
Synopsis
git-lfs-prune [OPTIONS]
Description
Deletes local copies of LFS files that have aged out and are no longer needed, freeing disk space. Prune walks the local object store and removes anything not retained by at least one of:
- HEAD’s tree in the current checkout
- HEAD’s tree in any linked worktree (
git worktree) - The stash
- A ‘recent ref’ — see RECENT FILES
- A ‘recent commit’ on HEAD or any recent ref — see RECENT FILES
- An unpushed commit — see UNPUSHED LFS FILES
In short: prune deletes objects you aren’t currently using and that aren’t ‘recent’, as long as they’ve been pushed. The reflog isn’t consulted, so LFS objects only reachable from orphaned commits are always deleted.
lfs.fetchexclude / lfs.fetchinclude (comma-separated gitignore-style patterns) restrict which paths each retention producer scans. See git-lfs-config(5).
Note: don’t run git lfs prune when multiple repositories share a custom storage directory. See lfs.storage in git-lfs-config(5) for the implications.
Options
Flags
-
-d,--dry-runDon’t actually delete anything; just report what would have been done -
-v,--verboseReport the full detail of what is/would be deleted -
--recentIgnore the recent-refs / recent-commits retention windows when computing what is prunable. Equivalent to settinglfs.fetchrecentrefsdaysandlfs.fetchrecentcommitsdaysto 0 for this invocation -
-f,--forceTreat every pushed object as prunable regardless of the recent-refs / recent-commits / unpushed retention rules. Pointers reachable from HEAD’s tree are still kept -
-c,--verify-remoteVerify with the remote that prunable objects exist there before deleting them locally. With this on, an object that can’t be served by the remote either halts the prune (default) or is dropped from the delete set (--when-unverified=continue). Reachable-but-unverified objects are reported asmissing on remote:; unreachable objects (orphans not in any commit) are silently passed through unless--verify-unreachableis also set. Overrideslfs.pruneverifyremotealways -
--no-verify-remoteOverridelfs.pruneverifyremotealways=trueand skip the remote verify pass for this invocation -
--verify-unreachableWhen--verify-remoteis in effect, verify orphan objects (not reachable from any commit) too. Without this, orphans pass through verification silently and are still pruned. Overrideslfs.pruneverifyunreachablealways -
--no-verify-unreachableOverridelfs.pruneverifyunreachablealways=trueand skip orphan verification for this invocation -
--when-unverified<MODE>What to do when--verify-remotefinds objects missing on the remote.halt(the default) refuses the prune and lists the missing OIDs;continuedrops them from the delete set and prunes the verified ones
Recent files
Prune keeps LFS files referenced by ‘recent’ commits so you can switch back to them without re-downloading. ‘Recent’ has the same meaning here as for git lfs fetch --recent, with an extra offset (default 3 days) so files you downloaded recently stick around for a while.
Settings:
lfs.pruneoffsetdays: extra days added to the fetch-recent windows. A ref or commit has to be at least this many days older than the oldest one--recentwould download for prune to consider it old enough to delete. Default 3. Only takes effect when the underlyinglfs.fetchrecent*dayssetting is non-zero.lfs.fetchrecentrefsdays,lfs.fetchrecentremoterefs,lfs.fetchrecentcommitsdays: same meaning as in git-lfs-fetch(1), used as the base for the offset above. A day value of 0 disables that retention dimension entirely (everything outside the other rules becomes prunable).
Unpushed lfs files
LFS files reachable from a commit that hasn’t reached the remote are never pruned, regardless of age — the local copy is the only one.
‘Pushed’ is determined by comparing local refs against the remote’s refs: any LFS file referenced by a commit reachable from a local ref but not from the corresponding remote ref is treated as unpushed. The pre-push hook uploads LFS objects before the remote branch updates, so this comparison gives an accurate picture.
See DEFAULT REMOTE for which remote anchors the comparison.
Verify remote
--verify-remote (-c) asks the remote whether every prunable LFS file has a server-side copy before deleting it locally. The UNPUSHED LFS FILES check above is usually enough, but --verify-remote adds belt-and-braces for cases where you want to be sure (at the cost of extra batch calls to the server).
Enable as the default by setting lfs.pruneverifyremotealways=true.
--verify-unreachable extends the verification pass to LFS objects that aren’t referenced by any commit (orphans — added to the index but never committed, or referenced only by orphaned commits). Without this flag, orphans pass through --verify-remote silently and are deleted. Enable as the default with lfs.pruneverifyunreachablealways=true.
By default, --verify-remote halts the entire prune if any object can’t be verified. Pass --when-unverified=continue to instead drop the unverifiable objects from the delete set and proceed with the rest.
See DEFAULT REMOTE for which remote is queried.
Default remote
origin is the default remote consulted for UNPUSHED LFS FILES and VERIFY REMOTE. Even with multiple remotes configured, prune treats this one as canonical — usually it’s the main central repo (or your fork of it), and a valid backup of your work.
If origin isn’t configured, prune treats every reachable LFS file as unpushed and effectively retains everything.
Override the canonical remote with lfs.pruneremotetocheck: set it to a different remote name to anchor against that one instead.
See also
git-lfs-fetch(1), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-pull
Name
git-lfs-pull — Download all Git LFS files for current ref and checkout
Synopsis
git-lfs-pull [OPTIONS] [ARGS]...
Description
Download all Git LFS files for current ref and checkout
Download Git LFS objects for the currently checked out ref, and update the working copy with the downloaded content if required.
This is generally equivalent to running git lfs fetch [options] [<remote>] followed by git lfs checkout. See git-lfs-checkout(1) for partial-clone, sparse-checkout, and bare-repository behavior (governed by the installed Git version and GIT_ATTR_SOURCE).
Requires git lfs install to have wired up the smudge filter. If the filter is missing, the fetch step still runs but the working-tree update is skipped with a hint to install.
Options
Arguments
-
<ARGS>Optional remote name followed by refs.The first positional argument is treated as a remote name when it resolves; any following arguments are refs to fetch. With no arguments, the default remote is used.
Flags
-
-I,--include<INCLUDE>Specifylfs.fetchincludejust for this invocation -
-X,--exclude<EXCLUDE>Specifylfs.fetchexcludejust for this invocation
Include and exclude
You can configure Git LFS to only fetch objects to satisfy references in certain paths of the repo, and/or to exclude certain paths of the repo, to reduce the time you spend downloading things you do not use.
In your Git configuration or in a .lfsconfig file, you may set
either or both of lfs.fetchinclude and lfs.fetchexclude to
comma-separated lists of paths. If lfs.fetchinclude is defined, Git
LFS objects will only be fetched if their path matches one in that
list, and if lfs.fetchexclude is defined, Git LFS objects will only
be fetched if their path does not match one in that list. Paths are
matched using wildcard matching as per gitignore(5).
Note that using the command-line options -I and -X override the
respective configuration settings. Setting either option to an empty
string clears the value.
Default remote
Without arguments, pull downloads from the default remote. The default
remote is the same as for git pull, i.e. based on the remote branch
you’re tracking first, or origin otherwise.
Examples
Download LFS objects for the current ref from the default remote, then update the working tree:
git lfs pull
Pull from a specific remote:
git lfs pull upstream
Pull, but only fetch LFS objects whose paths match a glob (overrides lfs.fetchinclude for this invocation):
git lfs pull -I "textures/**,*.psd"
Pull and skip a path subtree (overrides lfs.fetchexclude):
git lfs pull -X "media/reallybigfiles"
See also
git-lfs-fetch(1), git-lfs-checkout(1), gitattributes(5), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-push
Name
git-lfs-push — Push queued large files to the Git LFS endpoint
Synopsis
git-lfs-push [OPTIONS] <REMOTE> [ARGS]...
Description
Push queued large files to the Git LFS endpoint
Upload Git LFS files to the configured endpoint for the current Git remote. By default, filters out objects that are already referenced by the local clone of the remote (approximated via refs/remotes/<remote>/*); the server’s batch API dedupes again, so a missing local tracking ref doesn’t waste bandwidth.
Options
Arguments
-
<REMOTE>Remote to push to (e.g.origin). The remote’s tracking refs are excluded from the upload set so already-pushed objects aren’t sent again -
<ARGS>Refs (or, with--object-id, raw OIDs) to push. With--all, restricts the all-refs walk to these; with--stdin, ignored (a warning is emitted)
Flags
-
-d,--dry-runPrint the files that would be pushed, without actually pushing them -
-a,--allPush all objects reachable from the refs given as arguments.If no refs are provided, all local refs are pushed. Note this behavior differs from
git lfs fetch --all, which fetches every ref including refs outsiderefs/heads/refs/tags. If you’re migrating a repository, rungit lfs pushfor any additional remote refs that contain LFS objects not reachable from your local refs. -
-o,--object-idPush only the object OIDs listed on the command line (or read from stdin with--stdin), separated by spaces -
--stdinRead newline-delimited refs (or object IDs when using--object-id) from standard input instead of the command line
See also
git-lfs-fetch(1), git-lfs-pre-push(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-status
Name
git-lfs-status — Show the status of Git LFS files in the working tree
Synopsis
git-lfs-status [OPTIONS]
Description
Show the status of Git LFS files in the working tree
Display paths of Git LFS objects that have not been pushed to the Git LFS server (large files that would be uploaded by git push), that have differences between the index file and the current HEAD commit (large files that would be committed by git commit), or that have differences between the working tree and the index file (files that could be staged with git add).
Must be run in a non-bare repository.
Options
Flags
-
-p,--porcelainGive the output in an easy-to-parse format for scripts -
-j,--jsonWrite Git LFS file status information as JSON to standard output if the command exits successfully.Intended for interoperation with external tools. If
--porcelainis also provided, that option takes precedence.
See also
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-track
Name
git-lfs-track — View or add Git LFS paths to Git attributes
Synopsis
git-lfs-track [OPTIONS] [PATTERNS]...
Description
View or add Git LFS paths to Git attributes
Start tracking the given pattern(s) through Git LFS. The argument is written to .gitattributes. If no paths are provided, list the currently-tracked paths.
Per gitattributes(5), patterns use the gitignore(5) pattern rules to match paths. This means that patterns containing asterisk (*), question mark (?), and the bracket characters ([ and ]) are treated specially; to disable this behavior and treat them literally instead, use --filename or escape the character with a backslash.
Options
Arguments
<PATTERNS>File patterns to track (e.g.*.jpg,data/*.bin)
Flags
-
-v,--verboseLog files whichgit lfs trackwill touch. Disabled by default -
-d,--dry-runLog all actions that would normally take place (adding entries to.gitattributes, touching files on disk, etc.) without performing any mutative operations.Implicitly mocks the behavior of
--verbose, logging in greater detail what it is doing. Disabled by default. -
-j,--jsonWrite the currently tracked patterns as JSON to standard output.Intended for interoperation with external tools. Cannot be combined with any pattern arguments. If
--no-excludedis also provided, that option will have no effect. -
--filenameTreat the arguments as literal filenames, not as patterns.Any special glob characters in the filename will be escaped when writing the
.gitattributesfile. -
-l,--lockableMake the paths “lockable” — they should be locked to edit them, and will be made read-only in the working copy when not locked -
--not-lockableRemove the lockable flag from the paths so they are no longer read-only unless locked -
--no-excludedDon’t list patterns that are excluded in the output; only list patterns that are tracked -
--no-modify-attrsMake matched entries stat-dirty so that Git can re-index files you wish to convert to LFS.Does not modify any
.gitattributesfile.
Examples
List the patterns that Git LFS is currently tracking:
git lfs track
Configure Git LFS to track GIF files:
git lfs track "*.gif"
Configure Git LFS to track PSD files and make them read-only unless locked:
git lfs track --lockable "*.psd"
Configure Git LFS to track the file named project [1].psd:
git lfs track --filename "project [1].psd"
See also
git-lfs-untrack(1), git-lfs-install(1), gitattributes(5), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-uninstall
Name
git-lfs-uninstall — Remove Git LFS configuration
Synopsis
git-lfs-uninstall [OPTIONS] [MODE]
Description
Remove Git LFS configuration
Remove the lfs clean and smudge filters from the global Git config, and (when run from inside a Git repository) uninstall the Git LFS pre-push hook. Hooks that don’t match what we would write are left untouched.
Options
Arguments
<MODE>Optional mode. Withhooks, removes only the LFS git hooks and leaves the filter config alone (the inverse of--skip-repo)
Flags
-
-l,--localRemove thelfssmudge and clean filters from the local repository’s git config, instead of the global git config (~/.gitconfig) -
-w,--worktreeRemove thelfssmudge and clean filters from the current working tree’s git config, instead of the global git config (~/.gitconfig) or local repository’s git config ($GIT_DIR/config).If multiple working trees are in use, the Git config extension
worktreeConfigmust be enabled to use this option. If only one working tree is in use,--worktreehas the same effect as--local. Available only on Git v2.20.0 or later. -
--systemRemove thelfssmudge and clean filters from the system git config, instead of the global git config (~/.gitconfig) -
--file<PATH>Remove thelfssmudge and clean filters from the Git configuration file specified by<PATH> -
--skip-repoSkip cleanup of the local repo.Use if you want to uninstall the global LFS filters but not make changes to the current repo.
See also
git-lfs-install(1), git-worktree(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-unlock
Name
git-lfs-unlock — Remove “locked” setting for a file on the Git LFS server
Synopsis
git-lfs-unlock [OPTIONS] [PATHS]...
Description
Remove “locked” setting for a file on the Git LFS server
Removes the given file path as “locked” on the Git LFS server. Files must exist and have a clean git status before they can be unlocked. The --force flag will skip these checks.
Options
Arguments
<PATHS>Paths to unlock. Upstream’s CLI accepts a single path; ours accepts multiple (additive extension). Mutually exclusive with--id
Flags
-
-r,--remote<REMOTE>Specify the Git LFS server to use. Ignored if thelfs.urlconfig key is set -
-f,--forceTell the server to remove the lock, even if it’s owned by another user -
-i,--id<ID>Specify a lock by its ID instead of path. Mutually exclusive with the positional paths -
-j,--jsonWrite lock info as JSON to standard output if the command exits successfully.Intended for interoperation with external tools. If the command returns with a non-zero exit code, plain text messages are sent to standard error.
-
--ref<REFSPEC>Refspec to send with the unlock request (extension over upstream).Defaults to the current branch’s tracked upstream — same auto-resolution as
git lfs lock.
See also
git-lfs-lock(1), git-lfs-locks(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-untrack
Name
git-lfs-untrack — Remove Git LFS paths from Git attributes
Synopsis
git-lfs-untrack [PATTERNS]...
Description
Remove Git LFS paths from Git attributes
Stop tracking the given path(s) through Git LFS. The argument can be a glob pattern or a file path. The matching pointer files in history (and the objects in the local store) are left in place.
Options
Arguments
<PATTERNS>Paths or glob patterns to stop tracking
Examples
Configure Git LFS to stop tracking GIF files:
git lfs untrack "*.gif"
See also
git-lfs-track(1), git-lfs-install(1), gitattributes(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-version
Name
git-lfs-version — Print the git-lfs version banner and exit
Synopsis
git-lfs-version
Description
Print the git-lfs version banner and exit
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-clean
Name
git-lfs-clean — Git clean filter that converts large files to pointers
Synopsis
git-lfs-clean [PATH]
Description
Git clean filter that converts large files to pointers
Read the contents of a large file from standard input, and write a Git LFS pointer file for that file to standard output.
Clean is typically run by Git’s clean filter, configured by the repository’s Git attributes.
Clean is not part of the user-facing Git plumbing commands. To preview the pointer of a large file as it would be generated, see the git-lfs-pointer(1) command.
Options
Arguments
-
<PATH>Working-tree path of the file being cleaned.Substituted for
%fin any configuredlfs.extension.<name>.cleancommand.
See also
git-lfs-install(1), git-lfs-push(1), git-lfs-pointer(1), gitattributes(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-filter-process
Name
git-lfs-filter-process — Git filter process that converts between pointer and actual content
Synopsis
git-lfs-filter-process [OPTIONS]
Description
Git filter process that converts between pointer and actual content
Implement the Git process filter API, exchanging handshake messages and then accepting and responding to requests to either clean or smudge a file.
filter-process is always run by Git’s filter process, and is configured by the repository’s Git attributes.
In your Git configuration or in a .lfsconfig file, you may set either or both of lfs.fetchinclude and lfs.fetchexclude to comma-separated lists of paths. If lfs.fetchinclude is defined, Git LFS pointer files will only be replaced with the contents of the corresponding object file if their path matches one in that list, and if lfs.fetchexclude is defined, pointer files will only be replaced if their path does not match one in that list. Paths are matched using wildcard matching as per gitignore(5). Pointer files that are not replaced are simply copied to standard output without change.
The filter process uses Git’s pkt-line protocol to communicate, and is documented in detail in gitattributes(5).
Options
Flags
-
-s,--skipSkip automatic downloading of objects on clone or pull.Equivalent to
GIT_LFS_SKIP_SMUDGE=1. Wired up bygit lfs install --skip-smudge.
See also
git-lfs-clean(1), git-lfs-install(1), git-lfs-smudge(1), gitattributes(5), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-pointer
Name
git-lfs-pointer — Build, compare, and check pointers
Synopsis
git-lfs-pointer [OPTIONS]
Description
Build, compare, and check pointers
Build and optionally compare generated pointer files to ensure consistency between different Git LFS implementations.
Options
Flags
-
-f,--file<FILE>A local file to build the pointer from -
-p,--pointer<POINTER>A local file containing a pointer generated from another implementation.Compared to the pointer generated from
--file. -
--stdinRead the pointer from standard input to compare with the pointer generated from--file -
--checkRead the pointer from standard input (with--stdin) or the filepath (with--file).If neither or both of
--stdinand--fileare given, the invocation is invalid. Exits 0 if the data read is a valid Git LFS pointer, 1 otherwise. With--strict, exits 2 if the pointer is not byte-canonical. -
--strictWith--check, verify that the pointer is canonical (the one Git LFS would create).If it isn’t, exits 2. The default — for backwards compatibility — is
--no-strict. -
--no-strictDisable strict mode (paired with--strict) -
--no-extensionsBuild a plain pointer without running configuredlfs.extension.*clean commands. Default behavior is to chain through any extensions (and emit awarning:line on stderr); pass this to suppress both the chain and the warning
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-pre-push
Name
git-lfs-pre-push — Git pre-push hook implementation
Synopsis
git-lfs-pre-push [OPTIONS] <REMOTE> [URL]
Description
Git pre-push hook implementation
Respond to Git pre-push events. Reads the range of commits from stdin in the form <local-ref> <local-sha1> <remote-ref> <remote-sha1>, takes the remote name and URL as arguments, and uploads any Git LFS objects associated with those commits to the Git LFS API.
When pushing a new branch, the list of Git objects considered is every object reachable from the new branch. When deleting a branch, no LFS objects are pushed.
Options
Arguments
-
<REMOTE>Name of the remote being pushed to -
<URL>URL of the remote (informational; we use thelfs.urlconfig)
Flags
-d,--dry-runPrint the files that would be pushed, without actually pushing them
See also
git-lfs-clean(1), git-lfs-push(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-smudge
Name
git-lfs-smudge — Git smudge filter that converts pointer in blobs to the actual content
Synopsis
git-lfs-smudge [OPTIONS] [PATH]
Description
Git smudge filter that converts pointer in blobs to the actual content
Read a Git LFS pointer file from standard input and write the contents of the corresponding large file to standard output. If needed, download the file’s contents from the Git LFS endpoint. The argument, if provided, is only used for a progress bar.
Smudge is typically run by Git’s smudge filter, configured by the repository’s Git attributes.
In your Git configuration or in a .lfsconfig file, you may set either or both of lfs.fetchinclude and lfs.fetchexclude to comma-separated lists of paths. If lfs.fetchinclude is defined, Git LFS pointer files will only be replaced with the contents of the corresponding Git LFS object file if their path matches one in that list, and if lfs.fetchexclude is defined, Git LFS pointer files will only be replaced with the contents of the corresponding Git LFS object file if their path does not match one in that list. Paths are matched using wildcard matching as per gitignore(5). Git LFS pointer files that are not replaced with the contents of their corresponding object files are simply copied to standard output without change.
Without any options, git lfs smudge outputs the raw Git LFS content to standard output.
Options
Arguments
<PATH>Working-tree path of the file being smudged (currently unused)
Flags
-
--skipSkip automatic downloading of objects on clone or pull.Equivalent to
GIT_LFS_SKIP_SMUDGE=1. Wired up bygit lfs install --skip-smudge.
Environment
GIT_LFS_SKIP_SMUDGE- Disables the smudging process. For more information, see: git-lfs-config(5)
Known bugs
On Windows, Git before 2.34.0 does not handle files in the working tree larger than 4 gigabytes. Newer versions of Git, as well as Unix versions, are unaffected.
See also
git-lfs-install(1), gitattributes(5), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-post-checkout
Name
git-lfs-post-checkout — Git post-checkout hook implementation
Synopsis
git-lfs-post-checkout [ARGS]...
Description
Git post-checkout hook implementation
Respond to Git post-checkout events. Git invokes this hook with <rev-before> <ref-after> <is-branch-checkout>. We make sure that any files which are marked as lockable by git lfs track are read-only in the working copy, if not currently locked by the local user.
Options
Arguments
<ARGS>Positional arguments passed by git. Not normally invoked by hand
See also
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-post-commit
Name
git-lfs-post-commit — Git post-commit hook implementation
Synopsis
git-lfs-post-commit [ARGS]...
Description
Git post-commit hook implementation
Respond to Git post-commit events. Like git lfs post-merge, we make sure that any files which are marked as lockable by git lfs track are read-only in the working copy, if not currently locked by the local user.
Upstream optimizes by only checking files changed in HEAD; we currently scan the full work tree on every commit. The result is the same, but slower on large repositories.
Options
Arguments
<ARGS>Positional arguments passed by git. Not normally invoked by hand
See also
git-lfs-post-merge(1), git-lfs-track(1).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-post-merge
Name
git-lfs-post-merge — Git post-merge hook implementation
Synopsis
git-lfs-post-merge [ARGS]...
Description
Git post-merge hook implementation
Respond to Git post-merge events. Git invokes this hook with <is-squash>. We make sure that any files which are marked as lockable by git lfs track are read-only in the working copy, if not currently locked by the local user.
Options
Arguments
<ARGS>Positional arguments passed by git. Not normally invoked by hand
See also
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.
git-lfs-config
Name
git-lfs-config — Configuration options for git-lfs
Synopsis
git-lfs-config
Description
Configuration options for git-lfs
Configuration files
git-lfs reads its configuration from any file git config -l returns — that is, the system, global, and per-repository Git config files in their usual precedence order.
A small subset of keys may also be set in a .lfsconfig file at the repository root; see LFSCONFIG for the format and the list of keys allowed there. This is useful for settings every clone of the repository should share — most commonly lfs.url or an access mode — without forcing each user to configure them manually.
If .lfsconfig is missing on disk, the index is checked for it. If that’s also missing, HEAD is checked. In a bare repository, only HEAD is checked.
Settings from Git config files override .lfsconfig. This lets you change an LFS-related setting locally (e.g. point lfs.url at a staging server) without modifying the repository’s tracked configuration.
Most LFS settings live in the [lfs] section — keys of the form lfs.<foo>. A handful are scoped inside a particular remote’s config (remote.<name>.lfsurl and similar) and override the global lfs.* equivalents for that remote.
URL-specific overrides are written as lfs.<url>.<key>, where <url> is the LFS endpoint the setting should apply to. Longest-prefix match wins, so lfs.https://lfs.example.com/.locksverify overrides lfs.locksverify only for that endpoint.
General settings
-
lfs.url/remote.<remote>.lfsurlThe URL of the Git LFS API endpoint. Defaults to deriving the endpoint from the clone URL (
<clone-url>/info/lfs). The remote-scoped form overrides the general one for a particular remote. -
lfs.pushurl/remote.<remote>.lfspushurlSame idea but consulted only when pushing. Defaults to
lfs.urlor the derived endpoint. -
lfs.<url>.accessAuthentication mode for the LFS endpoint at
<url>. Eitherbasic(HTTP basic auth via the credential helper, the default after a successful round-trip) ornone(no authentication). Set viagit config --addwhen the access mode for an endpoint should be persisted; the auth-retry loop also writes this on a successful 401-fill cycle. -
core.askpass/GIT_ASKPASSProgram invoked when interactive credentials are needed against the LFS API. Stdout is read as the credential value. Same selection priority as Git uses:
GIT_ASKPASSenv beatscore.askpass, which beatsSSH_ASKPASS. -
credential.helper,credential.useHttpPath,credential.protectProtocolStandard Git credential-helper plumbing.
useHttpPath=truedistinguishes credentials per path within a host (so two paths on the same domain can have different passwords).protectProtocol=falselets credentials with carriage returns through (defaulttrue).
Upload and download transfer settings
-
lfs.concurrenttransfersNumber of object transfers running in parallel within a single LFS command. Default 8.
-
lfs.basictransfersonlyWhen
true, restrict the client to the basic HTTP upload/download adapter, ignoring more advanced transfers the server may advertise. Useful for working around broken intermediaries. Defaultfalse. -
lfs.transfer.batchSizeMax objects per
POST /objects/batchrequest. The transfer queue chunks the input list into runs of this size and issues one batch call per chunk. Default 100. Values < 1 are clamped to 1. Servers may refuse oversize batches with 413; lower this if you see those. -
lfs.transfer.enablehrefrewriteWhen
true, appliesurl.<base>.insteadOf/url.<base>.pushInsteadOfrewrites to the action URLs the batch endpoint hands back.pushInsteadOfis used for upload actions;insteadOfis used for downloads and for uploads whenpushInsteadOfisn’t set. Defaultfalse. -
lfs.<url>.contenttypeWhen
true(the default), the basic upload adapter sniffs the first 512 bytes of each object and sets theContent-Typeheader on the PUT to the detected MIME type. Set tofalseto sendapplication/octet-streamunconditionally — useful when a CDN rejects uploads based on content sniffing. The batch response’saction.headeralways wins if it pins a Content-Type itself. -
lfs.<url>.sshtransferWhether to use SSH (
git-lfs-authenticate) for the LFS endpoint at<url>. Values:negotiate(try SSH first, fall back to HTTPS — the default forssh://andgit@remotes),always, ornever.
Push settings
-
lfs.allowincompletepushWhen
true, allow a push to complete even if some LFS objects are missing from the local cache. By default (false), pre-push aborts and the user has to resolve the gap before pushing. -
lfs.<url>.locksverify(or unscopedlfs.locksverify)Controls whether the pre-push hook calls the lock API on the LFS endpoint to refuse pushes over files locked by someone else.
true: verify locks; halt the push if any are violated or the server is unreachable.false: skip the lock check entirely. Set this if you don’t use file locking, or your server enforces it server-side.- Unset: attempt the call; if it succeeds, persist
truefor next time. If the server returns 501 Not Implemented, persistfalse. If it fails for another reason, warn and continue. (Matches upstream’s first-call probe.)
Fetch settings
-
lfs.fetchincludeComma-separated list of
gitignore(5)-style patterns. When set, fetch only downloads objects whose path matches one of them. Empty string disables the filter. -
lfs.fetchexcludeInverse of
fetchinclude— fetch skips objects whose path matches. -
lfs.fetchrecentrefsdaysBranches whose tip commit lies within this many days of now are included by
fetch --recent. Only local refs are scanned unlesslfs.fetchrecentremoterefsis also set. Default 7. A value of 0 disables ref-window retention entirely. -
lfs.fetchrecentremoterefsWhen
true,fetch --recentalso scans the remote-tracking refs of the remote being fetched (useful for picking up branches you might check out later without first creating a tracking local ref). Defaulttrue. -
lfs.fetchrecentcommitsdaysIn addition to fetching the tip state of each recent ref, also fetch LFS objects referenced by commits within this many days of that ref’s tip. Default 0 (tip only).
-
lfs.fetchrecentalwaysWhen
true, always behave as if--recentwas passed. Defaultfalse.
Prune settings
-
lfs.pruneoffsetdaysExtra days added to the
lfs.fetchrecent*dayswindows when deciding what prune can delete. A ref or commit has to be at least this many days older than the oldest onefetch --recentwould download for prune to treat it as old enough to delete. Default 3. Only takes effect when the underlying fetch-recent setting is non-zero. -
lfs.pruneremotetocheckRemote to consult for UNPUSHED LFS FILES detection and
--verify-remote. Defaultorigin. See git-lfs-prune(1) for the full retention rules. -
lfs.pruneverifyremotealwaysWhen
true, always run prune as if--verify-remotewas passed. The pre-delete remote-presence check applies on every invocation. Use--no-verify-remoteto opt out for a single run. -
lfs.pruneverifyunreachablealwaysWhen
true, always run prune as if--verify-unreachablewas passed — also verify objects not reachable from any commit. Only meaningful when remote verification is on. Use--no-verify-unreachableto opt out for a single run.
Extensions
Git LFS extensions wrap each object’s bytes through an external program on the clean (commit) and smudge (checkout) paths — useful for repository-wide transforms like compression or encryption that should happen alongside pointerization.
-
lfs.extension.<name>.cleanCommand run when files are added to the index. Receives the raw bytes on stdin and is expected to emit transformed bytes on stdout.
-
lfs.extension.<name>.smudgeCommand run when files are written into the working copy. Reverses what
cleanproduced. -
lfs.extension.<name>.prioritySort order across extensions. Lower priorities run first on the clean side, last on the smudge side (so a chain
compress -> encryptreverses todecrypt -> decompress). Required when more than one extension is configured.
See git-lfs-ext(1) for inspecting the resolved chain.
Other settings
-
lfs.setlockablereadonly/GIT_LFS_SET_LOCKABLE_READONLYWhether files tracked as
lockablein.gitattributesare made read-only in the working copy unless the current user holds the lock. Defaulttrue. Set either to0/false/noto keep them writeable. -
lfs.skipdownloaderrors/GIT_LFS_SKIP_DOWNLOAD_ERRORSDon’t abort the smudge filter when an LFS download fails. The pointer is left in the working tree as-is, and the surrounding
git checkout(or whatever invoked smudge) reports success. Useful when you need to operate on a repository whose remote is temporarily unavailable, but be aware that scripts checking smudge exit status won’t see the failure. -
GIT_LFS_SKIP_SMUDGESkip pointer-to-content conversion in
git lfs smudgeandgit lfs filter-process. Equivalent to runninggit lfs install --skip-smudge(which sets it viafilter.lfs.process). Any value other than empty /0/falseenables it. -
GIT_LFS_SKIP_PUSHMake the pre-push hook a no-op. New LFS objects are not uploaded for the duration of the command. Same value semantics as
GIT_LFS_SKIP_SMUDGE.
Lfsconfig
.lfsconfig at the repository root uses the same format as .git/config. Only a restricted set of keys is honored here (the others are silently ignored), for security: a .lfsconfig from an untrusted clone shouldn’t be able to override credential helpers or arbitrary Git config.
Allowed keys:
lfs.allowincompletepushlfs.fetchexcludelfs.fetchincludelfs.gitprotocollfs.locksverifylfs.pushurllfs.skipdownloaderrorslfs.urllfs.<url>.accessremote.<name>.lfsurl
Examples
Configure a custom LFS endpoint for everyone who clones the repository:
git config -f .lfsconfig lfs.url https://lfs.example.com/foo/bar/info/lfs
Set the endpoint locally for the current user without touching .lfsconfig:
git config --global lfs.url https://lfs.example.com/foo/bar/info/lfs
Disable lock verification at the pre-push hook for a specific endpoint:
git config --global lfs.https://lfs.example.com/.locksverify false
Raise the concurrent-transfer ceiling on a fast link:
git config --global lfs.concurrenttransfers 16
Exclude a large media subtree from fetch/checkout:
git config lfs.fetchexclude "media/raw/**,**/*.psd"
See also
git-lfs(1), git-config(1), gitattributes(5), gitignore(5).
Reporting bugs
This command is from the Rust implementation of git-lfs, not the original Go implementation. Please report bugs to our issue tracker.