Help us learn about your current experience with the documentation. Take the survey.

Git LFS 开发指南

为了处理大型二进制文件,Git Large File Storage (LFS) 涉及多个协同工作的组件。 这些指南解释了在 GitLab LFS 代码库中工作的架构和代码流程。

有关用户文档,请参阅 Git Large File Storage

以下是使用 Git LFS 时 Git push 的高级流程图:

%%{init: { "fontFamily": "GitLab Sans" }}%%
flowchart LR
accTitle: Git pushes with Git LFS
accDescr: Explains how the LFS hook routes new files depending on type

A[Git push] -->B[LFS hook]
    B -->C[Pointers]
    B -->D[Binary files]
    C -->E[Repository]
    D -->F[LFS server]

以下是使用 Git LFS 时 Git pull 的高级流程图:

%%{init: { "fontFamily": "GitLab Sans" }}%%
flowchart LR
accTitle: Git pull using Git LFS
accDescr: Explains how the LFS hook pulls LFS assets from the LFS server, and everything else from the Git repository

A[User] -->|initiates<br>git pull| B[Repository]
    B -->|Pull data and<br>LFS transfers| C[LFS hook]
    C -->|LFS pointers| D[LFS server]
    D -->|Binary<br>files| C
    C -->|Pull data and<br>binary files| A

控制器和服务

Repositories::GitHttpClientController

此处定义的认证方法被所有其他 LFS 控制器继承。

Repositories::LfsApiController

#batch

认证后,batch 操作是 Git LFS 客户端在下载和上传(如 pull、push 和 clone)期间调用的第一个操作。

Repositories::LfsStorageController

#upload_authorize

向 Workhorse 提供有效载荷,包括 Workhorse 保存文件的路径。可能是远程对象存储。

#upload_finalize

处理来自 Workhorse 的请求,其中包含 Workhorse 已上传文件的信息(参见 此中间件),以便 gitlab 可以:

  • 创建一个 LfsObject
  • 使用 LfsObjectsProject 将现有的 LfsObject 连接到项目。

LfsObject 和 LfsObjectsProject

  • 对于具有给定 oid(文件的 SHA256 校验和)和文件大小的文件,只会创建一个 LfsObject
  • LfsObjectsProjectLfsObjectProject 关联。它们确定文件是否可以通过项目访问。
  • 这些对象也用于计算给定项目使用的 LFS 存储量。 更多信息,请参阅 ProjectStatistics#update_lfs_objects_size

Repositories::LfsLocksApiController

处理 LFS 的锁定 API。主要委托给相应的服务:

  • Lfs::LockFileService
  • Lfs::UnlockFileService
  • Lfs::LocksFinderService

这些服务创建和删除 LfsFileLock

#verify

  • 此端点响应一个有效载荷,允许客户端检查是否有任何正在推送的文件具有属于其他用户的锁定。
  • 可以设置客户端 lfs.locksverify 配置,以便如果存在属于其他用户的锁定,客户端会中止推送。
  • 其他用户的锁定存在性也在 服务器端验证

认证示例

%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
autonumber
    alt Over HTTPS
        Git client-->>Git client: user-supplied credentials
    else Over SSH
        Git client->>gitlab-shell: git-lfs-authenticate
        activate gitlab-shell
        activate GitLab Rails
        gitlab-shell->>GitLab Rails:  POST /api/v4/internal/lfs_authenticate
        GitLab Rails-->>gitlab-shell: token with expiry
        deactivate gitlab-shell
        deactivate GitLab Rails
    end
  1. 客户端可以配置为以几种不同的方式存储凭据。 请参阅 Git LFS 认证文档
  2. gitlab-shell 上运行 gitlab-lfs-authenticate。请参阅 关于 gitlab-lfs-authenticate 的 Git LFS 文档
  3. gitlab-shell 向 GitLab API 发出请求。
  4. 向 shell 返回令牌,用于后续请求。请参阅 关于认证的 Git LFS 文档

克隆示例

%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
    Note right of Git client: Typical Git clone things happen first
    Note right of Git client: Authentication for LFS comes next
    activate GitLab Rails
    autonumber
    Git client->>GitLab Rails: POST project/namespace/info/lfs/objects/batch
    GitLab Rails-->>Git client: payload with objects
    deactivate GitLab Rails
    loop each object in payload
    Git client->>GitLab Rails: GET project/namespace/gitlab-lfs/objects/:oid/ (<- This URL is from the payload)
    GitLab Rails->>Workhorse: SendfileUpload
    Workhorse-->> Git client: Binary data
    end
  1. Git LFS 请求下载文件,带有来自认证的授权头。
  2. gitlab 响应对象列表及其位置。请参阅 LfsApiController#batch
  3. Git LFS 对每个文件发出请求,获取先前响应中的 href。请参阅 如何使用基本传输模式处理下载
  4. 如果启用了远程对象存储,gitlab 会重定向到远程 URL。请参阅 SendFileUpload

推送示例

%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
    Note right of Git client: Typical Git push things happen first.
    Note right of Git client: Authentication for LFS comes next.
    autonumber
    activate GitLab Rails
        Git client ->> GitLab Rails: POST project/namespace/info/lfs/objects/batch
        GitLab Rails-->>Git client: payload with objects
    deactivate GitLab Rails
    loop each object in payload
    Git client->>Workhorse: PUT project/namespace/gitlab-lfs/objects/:oid/:size (URL is from payload)
    Workhorse->>GitLab Rails: PUT project/namespace/gitlab-lfs/objects/:oid/:size/authorize
    GitLab Rails-->>Workhorse: response with where path to upload
    Workhorse->>Workhorse: Upload
    Workhorse->>GitLab Rails: PUT project/namespace/gitlab-lfs/objects/:oid/:size/finalize
    end
  1. Git LFS 请求上传文件。
  2. gitlab 响应对象列表和上传位置。请参阅 LfsApiController#batch
  3. Git LFS 对每个文件发出请求,获取先前响应中的 href。请参阅 如何使用基本传输模式处理上传
  4. gitlab 响应一个有效载荷,包括 Workhorse 保存文件的路径。 可能是远程对象存储。请参阅 LfsStorageController#upload_authorize
  5. Workhorse 执行保存文件的工作。
  6. Workhorse 向 gitlab 发出请求,包含已上传文件的信息,以便 gitlab 可以创建一个 LfsObject。请参阅 LfsStorageController#upload_finalize

在项目归档中包含 LFS blob

下图说明了 GitLab 如何解析项目归档中的 LFS 文件:

%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
    autonumber
    Client->>+Workhorse: GET /group/project/-/archive/master.zip
    Workhorse->>+Rails: GET /group/project/-/archive/master.zip
    Rails->>+Workhorse: Gitlab-Workhorse-Send-Data git-archive
    Workhorse->>Gitaly: SendArchiveRequest
    Gitaly->>Git: git archive master
    Git->>Smudge: OID 12345
    Smudge->>+Workhorse: GET /internal/api/v4/lfs?oid=12345&gl_repository=project-1234
    Workhorse->>+Rails: GET /internal/api/v4/lfs?oid=12345&gl_repository=project-1234
    Rails->>+Workhorse: Gitlab-Workhorse-Send-Data send-url
    Workhorse->>Smudge: <LFS data>
    Smudge->>Git: <LFS data>
    Git->>Gitaly: <streamed data>
    Gitaly->>Workhorse: <streamed data>
    Workhorse->>Client: master.zip
  1. 用户从 UI 请求项目归档。
  2. Workhorse 将此请求转发给 Rails。
  3. 如果用户被授权下载归档,Rails 会回复一个 HTTP 头 Gitlab-Workhorse-Send-Data,其中包含一个 base64 编码的 JSON 有效载荷,前面加上 git-archive。此有效载荷包含再次用 base64 编码的 SendArchiveRequest 二进制消息。
  4. Workhorse 解码 Gitlab-Workhorse-Send-Data 有效载荷。如果归档已存在于归档缓存中,Workhorse 会发送该文件。否则,Workhorse 将 SendArchiveRequest 发送到相应的 Gitaly 服务器。
  5. Gitaly 服务器调用 git archive <ref> 来开始即时生成 Git 归档。如果启用了 include_lfs_blobs 标志,Gitaly 会使用 -c filter.lfs.smudge=/path/to/gitaly-lfs-smudge Git 选项启用自定义 LFS smudge 过滤器。
  6. git 使用 .gitattributes 文件识别可能的 LFS 指针时,git 调用 gitaly-lfs-smudge 并通过标准输入提供 LFS 指针。Gitaly 提供 GL_PROJECT_PATHGL_INTERNAL_CONFIG 作为环境变量,以便能够查找 LFS 对象。
  7. 如果解码了有效的 LFS 指针,gitaly-lfs-smudge 会向 Workhorse 发出内部 API 调用以从 GitLab 下载 LFS 对象。
  8. Workhorse 将此请求转发给 Rails。如果 LFS 对象存在并与项目关联,Rails 会发送 ArchivePath,要么是 LFS 对象所在的路径(对于本地磁盘),要么是预签名 URL(当启用对象存储时),使用 Gitlab-Workhorse-Send-Data HTTP 头,有效载荷前面加上 send-url
  9. Workhorse 检索文件并将其发送到 gitaly-lfs-smudge 进程,该进程将内容写入标准输出。
  10. git 读取此输出并将其发送回 Gitaly 进程。
  11. Gitaly 将数据发送回 Rails。
  12. 归档数据被发送回客户端。

在第 7 步中,gitaly-lfs-smudge 过滤器必须与 Workhorse 通信,而不是与 Rails 通信,否则会保存无效的 LFS blob。为了支持这一点,GitLab 更改了默认的 Linux 包配置,使 Gitaly 与 Workhorse 通信,而不是 Rails。

此更改的一个副作用:原始请求的关联 ID 不会为 Gitaly(或 gitaly-lfs-smudge)发出的内部 API 请求保留,例如第 8 步中发出的请求。这些 API 请求的关联 ID 是随机值,直到 此 Workhorse 问题 得到解决。

相关主题