Git LFS 개발 가이드라인

이 페이지에는 GitLab 팀원을 위한 개발자 중심 정보가 포함되어 있습니다. 사용자 설명서는 Git Large File Storage를 참조하세요.

컨트롤러 및 서비스

Repositories::GitHttpClientController

여기에 정의된 인증 방법은 모든 다른 LFS 컨트롤러에서 상속됩니다.

Repositories::LfsApiController

#batch

인증 후 batch 액션이 Git LFS 클라이언트에 의해 다운로드 및 업로드 (예: 풀, 푸시, 클론) 중에 호출되는 첫 번째 액션입니다.

Repositories::LfsStorageController

#upload_authorize

Workhorse에 payload를 제공하며, 파일을 저장할 Workhorse의 경로를 포함합니다. 원격 객체 리포지터리일 수도 있습니다.

#upload_finalize

이미 Workhorse가 업로드한 파일에 대한 정보를 포함하는 Workhorse로부터의 요청을 처리합니다 (이 middleware 참조), 이로써 gitlab은 다음을 할 수 있습니다:

  • LfsObject 생성
  • 기존의 LfsObjectLfsObjectsProject가 있는 프로젝트에 연결

LfsObject 및 LfsObjectsProject

  • 특정 oid (파일의 SHA256 체크섬) 및 파일 크기로 주어진 파일에 대해 하나의 LfsObject만 생성됩니다.
  • LfsObjectsProjectLfsObjectProject에 연결합니다. 파일이 프로젝트를 통해 액세스할 수 있는지를 결정합니다.
  • 이러한 객체들은 또한 특정 프로젝트가 사용 중인 LFS 리포지터리의 양을 계산하는 데 사용됩니다. 자세한 내용은 ProjectStatistics#update_lfs_objects_size 참조.

Repositories::LfsLocksApiController

LFS에 대한 잠금 API를 처리합니다. 주로 해당 서비스로 위임됩니다:

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

#verify

  • 이 엔드포인트는 클라이언트가 푸시되는 파일 중 다른 사용자에 의해 소유된 잠금을 확인할 수 있게 하는 payload로 응답합니다.
  • 클라이언트 측 lfs.locksverify 구성을 설정하여, 다른 사용자에 의해 소유된 잠금이 있으면 클라이언트가 푸시를 중단하도록 할 수 있습니다.
  • 다른 사용자가 소유한 잠금의 존재는 또한 서버 측에서도 유효성이 검사됩니다.

인증 예시

sequenceDiagram autonumber alt HTTPS를 통해 Git 클라이언트-->>Git 클라이언트: 사용자 제공 자격 증명 else SSH를 통해 Git 클라이언트->>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: 만료될 토큰 deactivate gitlab-shell deactivate GitLab Rails end
  1. 클라이언트는 자격 증명을 몇 가지 다른 방법으로 저장하도록 구성할 수 있습니다. Git LFS 인증에 대한 Git LFS 설명서를 참조하세요.
  2. gitlab-shell에서 gitlab-lfs-authenticate를 실행합니다. gitlab-lfs-authenticate에 관한 Git LFS 설명서를 참조하세요.
  3. gitlab-shell은 GitLab API에 요청을 생성합니다.
  4. 토큰으로 shell에 응답하며, 이것은 후속 요청에 사용됩니다. 인증에 관한 Git LFS 설명서를 참조하세요.

클론의 예시

sequenceDiagram Note right of Git 클라이언트: 전형적인 Git 클론 작업이 먼저 발생합니다 Note right of Git 클라이언트: LFS용 인증이 그 다음에 이루어집니다 activate GitLab Rails autonumber Git 클라이언트->>GitLab Rails: POST project/namespace/info/lfs/objects/batch GitLab Rails-->>Git 클라이언트: 객체가 있는 payload deactivate GitLab Rails loop payload에 있는 각 객체 Git 클라이언트->>GitLab Rails: 이전 응답의 `href`로부터 GET project/namespace/gitlab-lfs/objects/:oid/에 대한 요청 (<- 이 URL은 payload에서 가져온 것입니다) GitLab Rails->>Workhorse: SendfileUpload Workhorse-->> Git 클라이언트: 바이너리 데이터 end
  1. Git LFS는 인가 헤더와 함께 파일을 다운로드할 수 있는 능력을 요청합니다.
  2. gitlab는 객체 디렉터리 및 그들을 찾을 위치로 응답합니다. LfsApiController#batch를 참조하세요.
  3. Git LFS는 이전 응답 중 href에 대해 각 파일에 대한 요청을 생성합니다. 기본 전송 방식을 사용하여 다운로드가 처리되는 방법를 참조하세요.
  4. 원격 객체 리포지터리가 활성화되어 있는 경우, gitlab은 원격 URL로 리디렉션합니다. SendFileUpload를 참조하세요.

예시 푸시

sequenceDiagram Note right of Git client: 전형적인 Git 푸시 과정이 먼저 발생합니다. Note right of Git client: 다음으로 LFS용 인증이 이루어집니다. autonumber activate GitLab Rails Git client ->> GitLab Rails: 프로젝트/네임스페이스/info/lfs/objects/batch로 POST GitLab Rails-->>Git client: 객체가 포함된 페이로드 deactivate GitLab Rails loop 페이로드 내의 각 객체 Git client->>Workhorse: 페이로드에서 URL을 사용하여 프로젝트/네임스페이스/gitlab-lfs/objects/:oid/:size로 PUT Workhorse->>GitLab Rails: 프로젝트/네임스페이스/gitlab-lfs/objects/:oid/:size/authorize로 PUT GitLab Rails-->>Workhorse: 업로드할 경로와 관련한 응답 Workhorse->>Workhorse: 업로드 Workhorse->>GitLab Rails: 프로젝트/네임스페이스/gitlab-lfs/objects/:oid/:size/finalize로 PUT end
  1. Git LFS는 파일을 업로드할 수 있는 능력을 요청합니다.
  2. gitlab은 객체 디렉터리과 해당 객체를 찾기 위한 업로드로 응답합니다. 참조: LfsApiController#batch.
  3. Git LFS는 이전 응답의 href에 대해 각 파일에 대한 요청을 수행합니다. 참조: how uploads are handled with the basic transfer mode.
  4. gitlab은 파일을 저장하기 위한 경로를 포함한 페이로드로 응답합니다. 이는 원격 객체 리포지터리가 될 수 있습니다. 참조: LfsStorageController#upload_authorize.
  5. Workhorse가 파일을 저장하는 작업을 수행합니다.
  6. Workhorse는 업로드한 파일에 대한 정보와 함께 gitlab에 요청을 수행하여 LfsObject를 생성합니다. 참조: LfsStorageController#upload_finalize.

심층적인 탐구

2019년 4월, Francisco Javier López는 GitLab Git LFS 구현에 대한 심층적인 탐구(오로지 GitLab 팀 멤버: https://gitlab.com/gitlab-org/create-stage/-/issues/1)를 진행하여, 미래에 해당 코드베이스의 이 부분에서 작업할 수 있는 누구든지 도메인에 특화된 지식을 공유했습니다. YouTube 녹화Google 슬라이드, PDF에서 찾을 수 있습니다. 이 심층 탐구는 GitLab 11.10을 기준으로 했으며, 특정 세부 사항은 변경되었을 수 있지만 여전히 좋은 소개 자료로 사용될 것으로 기대됩니다.

프로젝트 아카이브에 LFS blob 포함하기

  • GitLab 13.5에 도입되었습니다.

다음 다이어그램은 GitLab이 프로젝트 아카이브에서 LFS 파일을 해결하는 방법을 보여줍니다.

sequenceDiagram autonumber 클라이언트->>+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 데이터> Smudge->>Git: <LFS 데이터> Git->>Gitaly: <스트림 데이터> Gitaly->>Workhorse: <스트림 데이터> Workhorse->>클라이언트: master.zip
  1. 사용자가 UI에서 프로젝트 아카이브를 요청합니다.
  2. Workhorse가 이 요청을 Rails로 전달합니다.
  3. 사용자가 아카이브를 다운로드할 수 있는 것이 인증되면, Rails는 Gitlab-Workhorse-Send-Data의 HTTP 헤더와 git-archive로 시작하는 base64로 인코딩된 JSON 페이로드를 제공합니다. 이 페이로드에는 또한 다시 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 스머지 필터를 활성화합니다.
  6. git.gitattributes 파일을 사용하여 가능한 LFS 포인터를 식별하면, gitgitaly-lfs-smudge를 호출하고 표준 입력을 통해 LFS 포인터를 제공합니다. Gitaly은 LFS 객체를 조회할 수 있도록 GL_PROJECT_PATHGL_INTERNAL_CONFIG를 환경 변수로 제공합니다.
  7. 유효한 LFS 포인터가 디코딩되면, gitaly-lfs-smudge은 워크호스에 내부 API 호출을 수행하여 GitLab에서 LFS 객체를 다운로드합니다.
  8. Workhorse는 이 요청을 Rails로 전달합니다. LFS 객체가 존재하고 프로젝트와 관련이 있는 경우, Rails는 Gitlab-Workhorse-Send-Data HTTP 헤더와 send-url로 시작하는 base64로 인코딩된 페이로드를 통해 LFS 객체가 위치한 경로(로컬 디스크의 경우) 또는 사전에 서명된 URL(객체 리포지터리가 활성화된 경우)를 송부합니다.
  9. Workhorse는 파일을 검색하여 gitaly-lfs-smudge 프로세스에 전송하고, 해당 내용을 표준 출력에 작성합니다.
  10. git은 이 출력을 읽어들이고, 그것을 다시 Gitaly 프로세스로 송부합니다.
  11. Gitaly은 데이터를 Rails로 송부합니다.
  12. 아카이브 데이터가 클라이언트로 송부됩니다.

7단계에서 gitaly-lfs-smudge 필터가 잘못된 LFS 블롭이 저장되지 않도록 하려면, Workhorse에게, Rails가 아닌 해결해야 합니다. 이를 위해 GitLab 13.5에서 기본 옴니버스 구성을 변경하여 Gitaly가 Rails가 아닌 Workhorse와 통신하도록 설정했습니다.

이 변경의 부작용 중 하나는: Gitaly 또는 gitaly-lfs-smudge에서 수행하는 내부 API 요청의 상관 ID가 원래 요청의 상관 ID가 유지되지 않고 무작위 값으로 유지되는 것이며, 이는 이 Workhorse 이슈가 해결될 때까지 유효합니다.

관련 주제

  • 블로그 글: Git LFS 시작하기
  • 사용자 설명서: Git Large File Storage (LFS)
  • Self-managed 인스턴스용 GitLab Git Large File Storage (LFS) 관리