Git LFS 개발 가이드라인
GitLab v19.1대용량 바이너리 파일을 처리하기 위해 Git Large File Storage(LFS)는 여러 구성 요소가 함께 작동합니다. 사용자 문서는 Git Large File Storage를 참조하세요. 다음은 Git LFS 사용 시 Git push 동작을 설명하는 상위 수준 다이어그램입니다:
대용량 바이너리 파일을 처리하기 위해 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
git pull| B[Repository]
B -->|Pull data and
LFS transfers| C[LFS hook]
C -->|LFS pointers| D[LFS server]
D -->|Binary
files| C
C -->|Pull data and
binary files| A
컨트롤러 및 서비스#
Repositories::GitHttpClientController#
여기에 정의된 인증 메서드는 다른 모든 LFS 컨트롤러가 상속합니다.
Repositories::LfsApiController#
#batch#
인증이 완료되면 batch 액션은 다운로드 및 업로드(pull, push, clone 등) 시 Git LFS
클라이언트가 처음으로 호출하는 액션입니다.
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::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
-
클라이언트는 몇 가지 방식으로 자격 증명을 저장하도록 구성할 수 있습니다. 인증에 관한 Git LFS 문서를 참조하세요.
-
gitlab-shell에서gitlab-lfs-authenticate실행.gitlab-lfs-authenticate에 관한 Git LFS 문서를 참조하세요. -
gitlab-shell이 GitLab API에 요청을 보냅니다. -
이후 요청에 사용되는 토큰으로 셸에 응답. 인증에 관한 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:
Smudge->>Git:
Git->>Gitaly:
-
사용자가 UI에서 프로젝트 아카이브를 요청합니다.
-
Workhorse가 이 요청을 Rails에 전달합니다.
-
사용자에게 아카이브 다운로드 권한이 있으면, Rails는
git-archive를 접두사로 붙인 base64 인코딩된 JSON 페이로드와 함께Gitlab-Workhorse-Send-DataHTTP 헤더로 응답합니다. 이 페이로드에는 다시 base64로 인코딩된SendArchiveRequest바이너리 메시지가 포함됩니다. -
Workhorse가
Gitlab-Workhorse-Send-Data페이로드를 디코딩합니다. 아카이브가 이미 아카이브 캐시에 존재하면 Workhorse가 해당 파일을 전송합니다. 그렇지 않으면 Workhorse가 적절한 Gitaly 서버에SendArchiveRequest를 전송합니다. -
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는 LFS 오브젝트 조회를 가능하게 하기 위해 환경 변수로GL_PROJECT_PATH와GL_INTERNAL_CONFIG를 제공합니다. -
유효한 LFS 포인터가 디코딩되면,
gitaly-lfs-smudge가 Workhorse에 내부 API 호출을 하여 GitLab에서 LFS 오브젝트를 다운로드합니다. -
Workhorse가 이 요청을 Rails에 전달합니다. LFS 오브젝트가 존재하고 프로젝트와 연결되어 있으면, Rails는 로컬 디스크의 경우 LFS 오브젝트가 저장된 경로를, 오브젝트 스토리지가 활성화된 경우 사전 서명된 URL을
send-url을 접두사로 붙인 페이로드와 함께Gitlab-Workhorse-Send-DataHTTP 헤더로 전송하여ArchivePath를 보냅니다. -
Workhorse가 파일을 가져와
gitaly-lfs-smudge프로세스에 전송하면, 해당 프로세스가 표준 출력에 내용을 씁니다. -
git이 이 출력을 읽어 Gitaly 프로세스에 다시 전송합니다. -
Gitaly가 데이터를 Rails에 다시 전송합니다.
-
아카이브 데이터가 클라이언트에 다시 전송됩니다.
7단계에서 gitaly-lfs-smudge 필터는 Rails가 아닌 Workhorse와 통신해야 합니다. 그렇지 않으면
잘못된 LFS blob이 저장됩니다. 이를 지원하기 위해 GitLab은
Gitaly가 Rails 대신 Workhorse와 통신하도록 기본 Linux 패키지 구성을 변경했습니다.
이 변경으로 인한 한 가지 부작용: 원래 요청의 correlation ID가 8단계에서 이루어진 것과 같이
Gitaly(또는 gitaly-lfs-smudge)에 의한 내부 API 요청에 보존되지 않습니다.
이 Workhorse 이슈가
해결될 때까지 해당 API 요청의 correlation ID는 임의 값입니다.
관련 주제#
-
블로그 포스트: Git LFS 시작하기
-
사용자 문서: Git Large File Storage (LFS)
-
GitLab Self-Managed를 위한 GitLab Git Large File Storage (LFS) 관리