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 푸시] -->B[LFS 훅] B -->C[포인터] B -->D[이진 파일] C -->E[저장소] D -->F[LFS 서버]

이 다이어그램은 Git LFS를 사용할 때 Git pull에 대한 고수준 설명입니다:

%%{init: { "fontFamily": "GitLab Sans" }}%% flowchart LR accTitle: Git LFS를 사용한 Git 풀 accDescr: LFS 훅이 LFS 서버에서 LFS 자산을 가져오고 Git 저장소에서 모든 다른 것을 가져오는 방법 설명 A[사용자] -->|시작<br>git pull| B[저장소] B -->|데이터 가져오기 및<br>LFS 전송| C[LFS 훅] 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를 생성합니다.
  • 기존 LfsObject를 프로젝트와 연결시키는 LfsObjectsProject를 생성합니다.

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 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 문서를 참조하세요.

  2. gitlab-lfs-authenticategitlab-shell에서 실행합니다.

    gitlab-lfs-authenticate에 관한 Git LFS 문서를 참조하세요.

  3. gitlab-shell은 GitLab API에 요청을 합니다.

  4. 셸에 토큰으로 응답하는 것은 후속 요청에 사용됩니다.

    인증에 관한 Git LFS 문서를 참조하세요.

예제 클론

%%{init: { "fontFamily": "GitLab Sans" }}%% sequenceDiagram Git 클라이언트 오른쪽 메모: 일반적인 Git 클론 작업이 먼저 수행됩니다. 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에 대해 각 파일 요청을 합니다.

    기본 전송 모드로 다운로드를 처리하는 방법을 참조하세요.

  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: POST project/namespace/info/lfs/objects/batch GitLab Rails-->>Git client: 객체가 포함된 페이로드 deactivate GitLab Rails loop 페이로드의 각 객체 Git client->>Workhorse: PUT project/namespace/gitlab-lfs/objects/:oid/:size (URL은 페이로드로부터) Workhorse->>GitLab Rails: PUT project/namespace/gitlab-lfs/objects/:oid/:size/authorize GitLab Rails-->>Workhorse: 업로드할 경로에 대한 응답 Workhorse->>Workhorse: 업로드 Workhorse->>GitLab Rails: PUT project/namespace/gitlab-lfs/objects/:oid/:size/finalize end
  1. Git LFS는 파일 업로드를 요청합니다.
  2. gitlab은 객체 목록과 그것을 찾기 위한 업로드를 응답합니다. 참조: LfsApiController#batch.
  3. Git LFS는 이전 응답의 href에 대한 각 파일 요청을 합니다. 참조: 기본 전송 모드로 uploads가 처리되는 방법.
  4. gitlab은 Workhorse가 파일을 저장할 경로를 포함한 페이로드로 응답합니다. 원격 객체 저장소가 될 수 있습니다. 참조: LfsStorageController#upload_authorize.
  5. Workhorse는 파일 저장 작업을 수행합니다.
  6. Workhorse는 업로드된 파일에 대한 정보를 gitlab에 요청하여 gitlabLfsObject를 생성할 수 있도록 합니다. 참조: LfsStorageController#upload_finalize.

심층 분석

2019년 4월, Francisco Javier López는 GitLab Git LFS 구현에 대한 심층 분석을 주최했습니다. 이 분석은 이 코드베이스의 일부에서 작업할 수 있는 모든 사람들과 도메인 특정 지식을 공유하기 위한 것입니다. YouTube에서 녹화된 영상Google SlidesPDF에서 슬라이드를 찾을 수 있습니다. 이 심층 분석은 GitLab 11.10 기준으로 정확했으며, 특정 세부 사항은 변경되었을 수 있지만, 여전히 좋은 소개로 작용합니다.

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

다음 다이어그램은 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는 Gitlab-Workhorse-Send-Data의 HTTP 헤더와 git-archive로 시작하는 base64로 인코딩된 JSON 페이로드로 응답합니다. 이 페이로드에는 다시 base64로 인코딩된 SendArchiveRequest 바이너리 메시지가 포함됩니다.

  4. Workhorse는 Gitlab-Workhorse-Send-Data 페이로드를 디코드합니다. 아카이브가 이미 아카이브 캐시에 존재하면, Workhorse는 해당 파일을 전송합니다. 그렇지 않으면, Workhorse는 적절한 Gitaly 서버에 SendArchiveRequest를 전송합니다.

  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 포인터를 식별하면, gitgitaly-lfs-smudge를 호출하고 표준 입력을 통해 LFS 포인터를 제공합니다. Gitaly는 LFS 객체의 조회를 활성화하기 위해 환경 변수로 GL_PROJECT_PATHGL_INTERNAL_CONFIG를 제공합니다.

  7. 유효한 LFS 포인터가 디코드되면, gitaly-lfs-smudge는 GitLab에서 LFS 객체를 다운로드하기 위해 Workhorse에 내부 API 호출을 수행합니다.

  8. Workhorse는 이 요청을 Rails에 전달합니다. LFS 객체가 존재하고 프로젝트와 연결되어 있으면, Rails는 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은 기본 Omnibus 구성을 변경하여 Gitaly와 Workhorse 간의 통신을 수행하도록 했습니다.

이 변경의 한 가지 부작용: 원본 요청의 상관 ID가 Gitaly(또는 gitaly-lfs-smudge)에 의해 수행되는 내부 API 요청에는 유지되지 않습니다. 8단계에서 수행된 요청과 같은 API 요청의 상관 ID는 무작위 값입니다. 이 Workhorse 문제가 해결될 때까지입니다.

관련 주제