Git LFS 개발 가이드

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

컨트롤러 및 서비스

Repositories::GitHttpClientController

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

Repositories::LfsApiController

#batch

인증 후 batch 액션은 Git LFS 클라이언트가 다운로드 및 업로드(풀, 푸시, 클론과 같은) 중에 호출하는 첫 번째 액션입니다.

Repositories::LfsStorageController

#upload_authorize

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

#upload_finalize

Workhorse로부터 요청을 처리하여, gitlab에서 다음을 할 수 있도록 파일에 대한 정보가 포함된 요청을 처리합니다. (이 미들웨어 참조)

  • LfsObject를 생성합니다.
  • 존재하는 LfsObjectLfsObjectsProject와 연결합니다.

LfsObject 및 LfsObjectsProject

  • 특정 oid (파일의 SHA256 체크섬)와 파일 크기를 가진 파일에 대해 하나의 LfsObject가 생성됩니다.
  • LfsObjectsProjectProjectLfsObject를 연결합니다. 이를 통해 프로젝트를 통해 파일에 액세스할 수 있는지 여부를 결정합니다.
  • 이러한 객체들은 또한 주어진 프로젝트가 사용 중인 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. 클라이언트는 자격 증명을 몇 가지 다른 방법으로 저장하도록 구성할 수 있습니다. 자세한 내용은 Git LFS documentation on authentication을 참조하세요.
  2. gitlab-lfs-authenticategitlab-shell에서 실행합니다. gitlab-lfs-authenticate에 관한 Git LFS documentation 참조.
  3. gitlab-shell은 GitLab API에 요청을 합니다.
  4. 토큰으로 shell에 응답하는 방법. 이 토큰은 후속 요청에서 사용됩니다. 인증에 관한 Git LFS documentation을 참조하세요.

예제 클론

%%{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 payload의 각 객체 Git 클라이언트->>GitLab Rails: 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 참조.

예제 푸시

%%{init: { "fontFamily": "GitLab Sans" }}%% sequenceDiagram Note right of Git 클라이언트: 일반적인 Git 푸시 작업이 먼저 발생합니다 Note right of Git 클라이언트: 다음으로 LFS 인증이 진행됩니다 autonumber activate GitLab Rails Git 클라이언트 ->> GitLab Rails: POST project/namespace/info/lfs/objects/batch GitLab Rails-->>Git 클라이언트: 파일에 대한 페이로드 deactivate GitLab Rails loop payload의 각 객체 Git 클라이언트->>Workhorse: PUT project/namespace/gitlab-lfs/objects/:oid/:size (URL은 payload에서 받은 것입니다) 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에 대해 각 파일에 대한 요청을 수행합니다. 기본 전송 모드로 업로드가 처리되는 방식 참조.
  4. gitlab은 파일을 저장할 Workhorse의 경로를 포함하는 페이로드로 응답합니다. 원격 객체 리포지터리일 수 있습니다. LfsStorageController#upload_authorize 참조.
  5. Workhorse는 파일을 저장하는 작업을 수행합니다.
  6. Workhorse는 업로드된 파일에 대한 정보를 포함한 요청을 gitlab에 수행하여, gitlab에서 LfsObject를 생성할 수 있도록 합니다. LfsStorageController#upload_finalize 참조.

심층 분석

2019년 4월, Francisco Javier López가 Deep Dive를 주최했는데(GitLab 팀 멤버 전용: https://gitlab.com/gitlab-org/create-stage/-/issues/1) 여기서는 이후에 해당 부분에서 작업할 수 있는 누구에게나 도메인 특정 지식을 공유했습니다.

에서 녹화된 것을 찾을 수 있으며, Google 슬라이드PDF에서 슬라이드를 찾을 수 있습니다. 본 심층 분석은 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는 base64로 인코딩된 JSON 페이로드와 함께 git-archive으로 앞에 두어진 Gitlab-Workhorse-Send-Data의 HTTP 헤더로 응답합니다. 이 페이로드에는 SendArchiveRequest 이진 메시지가 포함되어 있습니다. 이 메시지는 다시 한 번 base64로 인코딩됩니다.
  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는 LFS 객체 검색을 가능하게 하기 위해 GL_PROJECT_PATHGL_INTERNAL_CONFIG를 환경 변수로 제공합니다.
  7. 유효한 LFS 포인터가 디코딩된 경우, gitaly-lfs-smudge은 GitLab에서 LFS 객체를 다운로드하기 위해 Workhorse로 내부 API 호출을 수행합니다.
  8. Workhorse는 이 요청을 Rails로 전달합니다. LFS 객체가 존재하고 프로젝트와 연관되어 있는 경우, Rails은 send-url로 앞에 두어진 Gitlab-Workhorse-Send-Data HTTP 헤더와 함께(로컬 디스크의 경우 LFS 객체가 있는 경로 또는 객체 리포지터리가 활성화된 경우 미리 서명된 URL) ArchivePath를 보냅니다.
  9. Workhorse는 파일을 검색하여 gitaly-lfs-smudge 프로세스로 보내어 내용을 표준 출력에 기록합니다.
  10. git은 이 출력을 읽어 다시 Gitaly 프로세스로 보냅니다.
  11. Gitaly은 데이터를 다시 Rails로 보냅니다.
  12. 아카이브 데이터가 클라이언트로 다시 전송됩니다.

7단계에서 gitaly-lfs-smudge 필터는 Workhorse로 이야기해야 하며, Rails로는 이야기해서는 안 됩니다. 그렇지 않으면 잘못된 LFS 블롭이 저장됩니다. 이를 지원하기 위해 GitLab은 기본 Omnibus 구성을 변경하여 Gitaly가 Rails 대신에 Workhorse와 대화하도록 기본 구성으로 변경했습니다.

이 변경의 부작용 중 하나는 Gitaly(또는 gitaly-lfs-smudge)에 의해 내부 API 요청에서 원래 요청의 상관 ID가 보존되지 않는 점입니다. 이 Workhorse 이슈가 해결될 때까지 해당 API 요청의 상관 ID는 무작위 값입니다.

관련 주제