차이점 작업

이 페이지에는 차이점에 대한 개발자 설명서가 포함되어 있습니다. 사용자 설명서는 Merge Request의 차이점을 참조하세요.

우리는 차이점을 표시하기 위해 다양한 소스를 활용합니다. 이에는 다음이 포함됩니다.

  • Gitaly 서비스
  • 데이터베이스 (merge_request_diff_files를 통해)
  • Redis (캐시된 강조된 차이점)

심층 탐구

2019년 1월, Oswaldo Ferreira는 GitLab Diffs 및 차이점에 대한 Deep Dive를 진행했습니다 (GitLab 팀 멤버 전용: https://gitlab.com/gitlab-org/create-stage/-/issues/1). 이 Deep Dive는 이후에 이 코드베이스에서 작업하는 모든 사람들에게 도메인 별 지식을 공유하기 위한 것이었습니다.

이 심층 탐구에서 다룬 모든 내용은 GitLab 11.7 기준으로 정확했었으며, 구체적인 세부 사항은 그 이후에 변경되었을 수 있지만 여전히 좋은 소개 자료로 사용될 것입니다.

아키텍처 개요

Merge Request 차이점

Merge Request을 새로고침할 때(소스 브랜치에 푸시, 대상 브랜치로 강제 푸시하거나 대상 브랜치에 MR에서 가져온 커밋이 있는 경우) Gitlab::Git::Compare를 사용하여 기본(base)헤드(head) 데이터를 Gitaly를 통해 가져오고 그들 사이의 차이점은 Gitlab::Git::Diff.between을 통해 가져옵니다. 차이점 가져오기 과정은 단일 파일 차이점 크기 및 전체 차이점 크기를 일련의 상수 값으로 제한합니다. 원시 차이점 파일은 그런 다음 merge_request_diff_files 테이블에 영속화됩니다.

ApplicationSettings#diff_max_patch_bytes의 값의 10%보다 큰 차이점은 축소됩니다. 그러나 PostgreSQL에는 여전히 보관됩니다. 그러나 정의된 ‘안전한 한도’보다 큰 차이점 파일은 데이터베이스에 저장되지 않습니다.

Merge Request 차이점 페이지에서 차이점 정보를 표시하기 위해 다음을 수행합니다:

  1. 데이터베이스 merge_request_diff_files에서 모든 차이점 파일을 가져옵니다.
  2. 일괄적으로 이전새로운 파일 블롭들을 가져와서 다음을 수행합니다:
    • 이전 및 새로운 파일 내용을 강조 표시
    • 각 파일에 대해 어떤 뷰어를 사용해야 하는지 확인합니다(텍스트, 이미지, 삭제된 파일 등)
    • 파일 내용이 변경되었는지 확인
    • 외부 리포지터리에 보관되었는지 확인
    • 리포지터리 오류가 있는지 확인
  3. 차이점 파일이 캐시 가능한 경우(텍스트 기반), Gitlab::Diff::FileCollection::MergeRequestDiff를 사용하여 Redis에 캐시됩니다.

차이점 주의

차이점(비교)에 주석을 남길 때, 우리는 NoteDiffFile(실제 DiffNote와 연결된)에 축소된 차이점 버전을 영속화합니다. 따라서 파일의 차이점이 필요할 때마다 리포지터리에 접근하는 대신 다음을 수행합니다:

  1. NoteDiffFile#diff가 영속됐는지 확인하고 사용합니다.
  2. 그렇지 않으면, 현재 MR 버전인 경우, 영속된 MergeRequestDiffFile#diff를 사용합니다.
  3. 마지막 시나리오인 경우, 리포지터리로 이동하여 차이점을 가져옵니다.

차이점 한도

위에서 설명한 대로, 단일 차이점 파일과 전체 차이점의 크기를 제한합니다. 차이점 파일이 축소되는 시나리오와 전혀 표시되지 않는 차이점 파일이 있는 시나리오가 있으며, 사용자는 Blob 뷰로 안내됩니다.

차이점 모음 한도

모든 차이점 파일 모음에 적용되는 한도입니다. 파일 수, 라인 수 및 파일 크기가 고려됩니다.

Gitlab::Git::DiffCollection.collection_limits[:safe_max_files] = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_files] = 100

100개의 파일이 이미 렌더링되었으면 파일 차이점이 축소됩니다(확장 가능).

Gitlab::Git::DiffCollection.collection_limits[:safe_max_lines] = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] = 5000

5000줄이 이미 렌더링되었으면 파일 차이점이 축소됩니다(확장 가능).

Gitlab::Git::DiffCollection.collection_limits[:safe_max_bytes] = Gitlab::Git::DiffCollection.collection_limits[:safe_max_files] * 5.kilobytes = 500.kilobytes

500킬로바이트가 이미 렌더링되었으면 파일 차이점이 축소됩니다(확장 가능).

Gitlab::Git::DiffCollection.collection_limits[:max_files] = Commit::DIFF_HARD_LIMIT_FILES = 1000

1000개의 파일이 이미 렌더링되었으면 더 이상 파일이 전혀 렌더링되지 않습니다.

Gitlab::Git::DiffCollection.collection_limits[:max_lines] = Commit::DIFF_HARD_LIMIT_LINES = 50000

50,000줄이 이미 렌더링되었으면 더 이상 파일이 전혀 렌더링되지 않습니다.

Gitlab::Git::DiffCollection.collection_limits[:max_bytes] = Gitlab::Git::DiffCollection.collection_limits[:max_files] * 5.kilobytes = 5000.kilobytes

5메가바이트가 이미 렌더링되었으면 더 이상 파일이 전혀 렌더링되지 않습니다.

모든 모음 한도 매개변수는 Gitaly로 보내고 적용됩니다. 즉, 한도를 초과한 후 Gitaly에서는 안전한 양의 데이터만 반환합니다. merge_request_diff_files에 영속화해야 합니다.

개별 차이점 파일 한도

각 차이점 파일에 적용되는 한도입니다. 파일 수, 라인 수 및 파일 크기가 고려됩니다.

확장 가능한 패치(축소)

ApplicationSettings#diff_max_patch_bytes에서 설정된 값의 10%를 초과할 때 차이 패치가 축소됩니다. 즉, 최대 허용 값이 100kb인 경우 10kb와 동일합니다. 패치의 크기가 ApplicationSettings#diff_max_patch_bytes를 초과하지 않으면 차이점이 영속화되고 확장 가능합니다.

이 명명법(축소)은 Gitaly에서도 사용되지만 이 한도는 GitLab에서만 사용되는 것입니다(하드코딩 - Gitaly로 전송되지 않음). Gitaly는 컬렉션 한도를 초과한 경우 Diff.Collapsed (RPC)만 반환합니다.

확장할 수 없는 패치(너무 큼)

패치가 ApplicationSettings#diff_max_patch_bytes보다 크면 렌더링되지 않습니다. 사용자는 ‘표시할만큼 파일 크기가 너무 큽니다.’ 메시지와 해당 커밋의 파일만 보기 위한 버튼을 볼 수 있습니다.

Commit::DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] = 5000

5000줄 이상이 있으면 파일 차이점이 억제됩니다(기술적으로 축소되지 않지만 동일하게 동작하고 확장 가능합니다).

이 한도는 하드코딩되어 있으며 GitLab에만 적용됩니다.

뷰어

models/diff_viewer/*에서 찾을 수 있는 Diff 뷰어는 각 차이점 파일 유형에 대한 메타데이터를 매핑하는 데 사용되는 클래스입니다. 이것은 이러한 클래스가 바이너리인지, 그것을 렌더링하는 데 사용해야 하는 부분이 무엇인지 또는 이 클래스가 담당하는 파일 확장자에 대한 정보를 갖고 있습니다.

DiffViewer::Base블롭 (이전 및 새로운 버전) 내용, 확장자 및 파일 유형을 확인하여 렌더링할 수 있는지 여부를 확인합니다.

대상 브랜치의 HEAD에 대한 Merge Request 차이점

Merge Request 차이점은 기록적으로 git diff target...source로 계산되었습니다. 이는 소스 브랜치의 HEAD와 대상 브랜치 및 소스의 공통 조상 또는 Merge 기저점을 비교합니다. 이 솔루션은 대상 브랜치에 일부 변경 사항이 포함되기 시작할 때까지 잘 작동합니다: 다음 사례를 고려해보십시오. 소스 브랜치가 feature_a이고 대상 브랜치가 main인 경우를 생각해보십시오.

  1. main에서 feature_a의 새 브랜치 feature_a을 만들고 해당 브랜치에서 file_afile_b를 제거하십시오.
  2. mainfile_a를 제거하는 커밋을 추가하십시오.

Merge Request 차이점은 여전히 file_a 제거를 포함하고 있지만 실제 차이점은 mainHEAD에 대한 file_b 제거만 포함합니다. 이러한 중복 변경 사항이 포함된 차이점을 검토하기가 더 어렵습니다.

업데이트된 차이점을 표시하기 위해 대상 브랜치의 HEAD와 비교된 Merge Request 차이점을 소개했습니다: 대상 브랜치가 소스 브랜치로 인위적으로 Merge되고 나면 결과적으로 Merge 참조가 소스 브랜치와 비교되어 정확한 차이점을 계산합니다.

우리가 “차이점에 대한 Merge 참조 사용”“차이점에서 Merge 충돌”에 대한 에픽을 완료할 때까지 main (기본)main (HEAD) 옵션 모두 Merge Request에서 표시할 수 있습니다.

Merge 참조 head 옵션

main (HEAD) 옵션은 향후에 main (기본)을 대체하는 것을 목표로 합니다.

두 옵션에 대한 주석을 지원하기 위해 main (기본) 버전에 대한 차이점 주석 위치를 Note#positionNote#original_position 열에 저장하고 main (HEAD) 버전을 위해 DiffNotePosition이 도입되었습니다(12.10에서 소개).

Merge 참조 차이점을 다룰 때 주요한 문제 중 하나는 Merge 충돌입니다. 대상 브랜치와 소스 브랜치에 Merge 충돌이 있으면 브랜치가 자동으로 Merge될 수 없습니다. 유튜브 녹화는 이 문제와 에픽의 동기에 대한 빠른 소개입니다.

13.5에서 양쪽 수정된 Merge 충돌에 대한 솔루션이 도입되었습니다. 그러나 앞으로 다룰 다른 Merge 충돌 유형이 더 있습니다.

```