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。 LfsObjectsProject将LfsObject与Project关联。它们确定文件是否可以通过项目访问。- 这些对象也用于计算给定项目使用的 LFS 存储量。
更多信息,请参阅
ProjectStatistics#update_lfs_objects_size。
Repositories::LfsLocksApiController
处理 LFS 的锁定 API。主要委托给相应的服务:
Lfs::LockFileServiceLfs::UnlockFileServiceLfs::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
- 客户端可以配置为以几种不同的方式存储凭据。 请参阅 Git LFS 认证文档。
- 在
gitlab-shell上运行gitlab-lfs-authenticate。请参阅 关于gitlab-lfs-authenticate的 Git LFS 文档。 gitlab-shell向 GitLab API 发出请求。- 向 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
- Git LFS 请求下载文件,带有来自认证的授权头。
gitlab响应对象列表及其位置。请参阅 LfsApiController#batch。- Git LFS 对每个文件发出请求,获取先前响应中的
href。请参阅 如何使用基本传输模式处理下载。 - 如果启用了远程对象存储,
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
- Git LFS 请求上传文件。
gitlab响应对象列表和上传位置。请参阅 LfsApiController#batch。- Git LFS 对每个文件发出请求,获取先前响应中的
href。请参阅 如何使用基本传输模式处理上传。 gitlab响应一个有效载荷,包括 Workhorse 保存文件的路径。 可能是远程对象存储。请参阅 LfsStorageController#upload_authorize。- Workhorse 执行保存文件的工作。
- 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
- 用户从 UI 请求项目归档。
- Workhorse 将此请求转发给 Rails。
- 如果用户被授权下载归档,Rails 会回复一个 HTTP 头
Gitlab-Workhorse-Send-Data,其中包含一个 base64 编码的 JSON 有效载荷,前面加上git-archive。此有效载荷包含再次用 base64 编码的SendArchiveRequest二进制消息。 - Workhorse 解码
Gitlab-Workhorse-Send-Data有效载荷。如果归档已存在于归档缓存中,Workhorse 会发送该文件。否则,Workhorse 将SendArchiveRequest发送到相应的 Gitaly 服务器。 - Gitaly 服务器调用
git archive <ref>来开始即时生成 Git 归档。如果启用了include_lfs_blobs标志,Gitaly 会使用-c filter.lfs.smudge=/path/to/gitaly-lfs-smudgeGit 选项启用自定义 LFS smudge 过滤器。 - 当
git使用.gitattributes文件识别可能的 LFS 指针时,git调用gitaly-lfs-smudge并通过标准输入提供 LFS 指针。Gitaly 提供GL_PROJECT_PATH和GL_INTERNAL_CONFIG作为环境变量,以便能够查找 LFS 对象。 - 如果解码了有效的 LFS 指针,
gitaly-lfs-smudge会向 Workhorse 发出内部 API 调用以从 GitLab 下载 LFS 对象。 - Workhorse 将此请求转发给 Rails。如果 LFS 对象存在并与项目关联,Rails 会发送
ArchivePath,要么是 LFS 对象所在的路径(对于本地磁盘),要么是预签名 URL(当启用对象存储时),使用Gitlab-Workhorse-Send-DataHTTP 头,有效载荷前面加上send-url。 - Workhorse 检索文件并将其发送到
gitaly-lfs-smudge进程,该进程将内容写入标准输出。 git读取此输出并将其发送回 Gitaly 进程。- Gitaly 将数据发送回 Rails。
- 归档数据被发送回客户端。
在第 7 步中,gitaly-lfs-smudge 过滤器必须与 Workhorse 通信,而不是与 Rails 通信,否则会保存无效的 LFS blob。为了支持这一点,GitLab 更改了默认的 Linux 包配置,使 Gitaly 与 Workhorse 通信,而不是 Rails。
此更改的一个副作用:原始请求的关联 ID 不会为 Gitaly(或 gitaly-lfs-smudge)发出的内部 API 请求保留,例如第 8 步中发出的请求。这些 API 请求的关联 ID 是随机值,直到 此 Workhorse 问题 得到解决。