Git LFS 개발 지침

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

이 다이어그램은 Git LFS를 사용할 때 Git push의 고수준 설명입니다.

%%{init: { "fontFamily": "GitLab Sans" }}%% flowchart LR accTitle: Git LFS를 사용하여 Git이 푸시됨 accDescr: 새 파일을 종류에 따라 라우팅하는 LFS 후크의 작동 방식을 설명합니다. A[Git push] -->B[LFS hook] B -->C[포인터] B -->D[이진 파일] C -->E[저장소] D -->F[LFS 서버]

이 다이어그램은 Git LFS를 사용할 때 Git pull의 고수준 설명입니다.

%%{init: { "fontFamily": "GitLab Sans" }}%% flowchart LR accTitle: Git LFS를 사용한 Git pull accDescr: LFS 후크가 LFS 자산을 LFS 서버로부터 가져오고, 그 외 모든 것을 Git 저장소에서 가져오는 방법을 설명합니다. A[사용자] -->|시작<br>git pull| B[저장소] B -->|데이터를 가져오고<br>LFS 이전| C[LFS hook] C -->|LFS 포인터| D[LFS 서버] D -->|이진<br>파일| C C -->|데이터를 가져오고<br>이진 파일| A

컨트롤러 및 서비스

Repositories::GitHttpClientController

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

Repositories::LfsApiController

#batch

인증 후 batch 액션은 Git LFS 클라이언트가 다운로드 및 업로드(예: pull, push 및 clone) 중에 호출하는 첫 번째 액션입니다.

Repositories::LfsStorageController

#upload_authorize

Workhorse에 파일을 저장할 경로를 포함하여 페이로드를 제공합니다. 원격 객체 저장소일 수도 있습니다.

#upload_finalize

Workhorse로부터 이미 업로드된 파일에 대한 정보가 포함된 요청을 처리하여 gitlab이 다음 중 하나를 수행할 수 있게 합니다.

  • LfsObject를 생성합니다.
  • LfsObjectLfsObjectsProject와 연결하여 프로젝트에서 LfsObject에 액세스할 수 있도록 합니다.

LfsObject 및 LfsObjectsProject

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

Repositories::LfsLocksApiController

LFS의 잠금 API를 처리합니다. 대부분 관련 서비스에 위임합니다:

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

이 엔드포인트는 다른 사용자에게 속한 잠금이 있는 파일을 푸시하려는 경우 파일이 푸시되고 있는지 확인할 수 있게 하는 페이로드로 응답합니다. 클라이언트 측 lfs.locksverify 설정을 하여 다른 사용자에게 속한 잠금이 있는 경우 클라이언트가 푸시를 중단하도록 설정할 수 있습니다. 다른 사용자에게 속한 잠금의 존재는 또한 서버 측에서 유효성이 검사됩니다.

예제 인증

%%{init: { "fontFamily": "GitLab Sans" }}%% 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. 클라이언트는 자격 증명을 몇 가지 다른 방법으로 저장하도록 구성할 수 있습니다. 자세한 내용은 Authentication을 참조하십시오.
  2. gitlab-shell에서 gitlab-lfs-authenticate를 실행합니다. gitlab-lfs-authenticate에 관한 Git LFS 문서를 참조하십시오.
  3. gitlab-shell이 GitLab API에 요청을 보냅니다.
  4. 새로운 요청에서 사용되는 토큰으로 쉘에 응답합니다. 자격 증명에 관한 Git LFS 문서를 참조하십시오.

예제 클론

%%{init: { "fontFamily": "GitLab Sans" }}%% 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 클라이언트: 객체가 포함된 페이로드 deactivate GitLab Rails loop 페이로드의 각 객체 Git 클라이언트->>GitLab Rails: GET project/namespace/gitlab-lfs/objects/:oid/ (<- 이 URL은 페이로드에서 비롯됨) GitLab Rails->>Workhorse: SendfileUpload Workhorse-->> Git 클라이언트: 바이너리 데이터 end
  1. Git LFS는 권한 부여 헤더로 파일을 다운로드할 수 있는 능력을 요청합니다.
  2. gitlab은 객체 목록 및 객체의 위치로 응답합니다. LfsApiController#batch를 참조하십시오.
  3. Git LFS는 이전 응답의 href에 대해 각 파일을 요청합니다. downloads are handled with the basic transfer mode를 참조하십시오.
  4. 원격 객체 저장소가 활성화되어 있는 경우 gitlab은 원격 URL로 리디렉션합니다. SendFileUpload를 참조하십시오.

예시 푸시

%%{init: { "fontFamily": "GitLab Sans" }}%% 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 게시 GitLab Rails-->>Git client: 객체가 담긴 페이로드 deactivate GitLab Rails loop 페이로드의 각 객체 반복 Git client->>Workhorse: 페이로드에서 URL을 통한 프로젝트/네임스페이스/gitlab-lfs/objects/:oid/:size 업로드 (URL은 페이로드에서 가져옴) 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를 통해 각 파일에 대한 요청을 합니다. 기본 전송 방식으로 어떻게 업로드를 처리하는 지를 확인하세요.
  4. gitlab은 파일을 저장할 경로를 포함한 페이로드로 응답합니다. 원격 객체 스토리지가 될 수 있습니다. LfsStorageController#upload_authorize를 참조하세요.
  5. Workhorse가 파일을 저장하는 작업을 합니다.
  6. Workhorse가 업로드된 파일에 대한 정보를 가지고 gitlab에 요청하여 LfsObject를 생성합니다. LfsStorageController#upload_finalize를 참조하세요.

심층 분석

2019년 4월, Francisco Javier López은 Deep Dive를 진행했습니다(기술팀 멤버 전용: https://gitlab.com/gitlab-org/create-stage/-/issues/1) GitLab의 Git LFS 구현을 공유하여 미래에 이 코드베이스에서 작업할 수 있는 사람들에게 도메인별 높은 수준의 지식을 전달하였습니다. YouTube에서 동영상, 그리고 Google SlidesPDF에 슬라이드를 찾을 수 있습니다. 본 딥 다이브는 GitLab 11.10 때 정확했으며, 특정 세부 사항이 변경되었을 수 있지만 여전히 좋은 소개 자료로 사용될 수 있을 것입니다.

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

다음 다이어그램은 GitLab이 프로젝트 아카이브의 LFS 파일을 어떻게 해결하는 지를 보여줍니다.

%%{init: { "fontFamily": "GitLab Sans" }}%% 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 data> Smudge->>Git: <LFS data> Git->>Gitaly: <streamed data> Gitaly->>Workhorse: <streamed data> Workhorse->>Client: master.zip
  1. 사용자가 UI에서 프로젝트 아카이브를 요청합니다.
  2. Workhorse가 이 요청을 Rails로 전달합니다.
  3. 사용자가 아카이브를 다운로드할 수 있는 경우, Rails은 Gitlab-Workhorse-Send-Data HTTP 헤더와 base64로 인코딩된 JSON 페이로드를 가지고 git-archive로 시작하는 이진 메시지인 SendArchiveRequest를 응답으로 보냅니다.
  4. Workhorse는 Gitlab-Workhorse-Send-Data 페이로드를 디코딩합니다. 아카이브가 이미 아카이브 캐시에 있는 경우, Workhorse는 해당 파일을 보냅니다. 그렇지 않은 경우, Workhorse는 SendArchiveRequest를 적절한 Gitaly 서버로 전송합니다.
  5. Gitaly 서버는 동적으로 Git 아카이브 생성을 시작하기 위해 git archive <ref>를 호출합니다. include_lfs_blobs 플래그가 활성화되어 있는 경우, Gitaly는 -c filter.lfs.smudge=/path/to/gitaly-lfs-smudge Git 옵션을 사용하여 사용자 정의 LFS 스머지 필터를 활성화합니다.
  6. git.gitattributes 파일을 사용하여 가능한 LFS 포인터를 식별하면, gitgitaly-lfs-smudge를 호출하고 표준 입력을 통해 LFS 포인터를 제공합니다. Gitaly은 GL_PROJECT_PATHGL_INTERNAL_CONFIG 환경 변수를 제공하여 LFS 객체를 찾도록 합니다.
  7. 유효한 LFS 포인터가 해독되면, gitaly-lfs-smudge가 Workhorse로 내부 API 호출을 하여 LFS 객체를 GitLab에서 다운로드합니다.
  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 필터는 Rails가 아닌 Workhorse로 통신해야 합니다. 그렇지 않을 경우 잘못된 LFS 블롭이 저장됩니다. 이를 지원하기 위해 GitLab은 기본 옴니버스 구성을 변경하여 Gitaly가 Rails가 아닌 Workhorse와 통신하도록 하였습니다.

이 변경의 부작용 중 하나는, Gitaly (또는 gitaly-lfs-smudge)에 의해 내부 API 요청이 이루어질 때 원본 요청의 상관 ID가 보존되지 않으며, 랜덤 값으로 설정됩니다. 이러한 API 요청의 상관 ID는 이 Workhorse 이슈가 해결될 때까지 유효하지 않습니다.

관련 주제

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