처리 차이 사항

이 페이지에는 차이 사항에 대한 개발자 설명서가 포함되어 있습니다. 사용자 설명서는 병합 요청의 차이 사항을 참조하십시오.

차이 사항을 제공하는 데 다양한 소스를 활용합니다. 이에는 다음이 포함됩니다.

  • Gitaly 서비스
  • 데이터베이스 (merge_request_diff_files를 통해)
  • Redis (캐시된 하이라이트된 차이 사항)

심층 분석

1월 2019년, Oswaldo Ferreira는 GitLab Diffs 및 차이 사항에 대한 Deep Dive(내부 GitLab 팀 멤버 전용: https://gitlab.com/gitlab-org/create-stage/-/issues/1)를 주관하여 해당 코드베이스에서 작업하는 모든 사람과 특정 도메인 지식을 공유했습니다.

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

아키텍처 개요

병합 요청 차이 사항

병합 요청을 새로 고칠 때(소스 브랜치로 푸시하거나 대상 브랜치로 강제로 푸시하는 경우 또는 대상 브랜치에 MR(Merge Request)에서의 어떤 커밋이든 포함될 경우), Gitlab::Git::Compare를 사용하여 비교 정보를 가져오고, 이를 통해 Gitaly를 사용하여 basehead 데이터를 가져오고 Gitlab::Git::Diff.between을 통해 그들 사이의 차이를 가져옵니다. 차이 사항 검색 과정에서는 단일 파일 차이 크기를 _제한_하고 전체 차이의 크기를 일련의 상수 값으로 처리합니다. 그런 다음 원시 차이 파일은 merge_request_diff_files 테이블에 유지됩니다.

ApplicationSettings#diff_max_patch_bytes 값의 10% 이상인 차이 사항은 접혀집니다. 그러나 그럼에도 불구하고 이러한 차이 사항은 PostgreSQL에 유지됩니다. 그러나 데이터베이스에 유지되지 않는 _안전한 한계_보다 큰 차이 파일은 포함되지 않습니다. 병합 요청 차이 사항 페이지에서 차이 사항 정보를 표시하기 위해 다음을 수행합니다.

  1. 데이터베이스 merge_request_diff_files에서 모든 차이 파일 가져오기
  2. 배치로 이전새로운 파일 블롭 가져오기:
    • 이전 및 새로운 파일 내용 강조 표시
    • 각 파일에 대해 어떤 뷰어를 사용해야 하는지 파악
    • 파일 내용이 변경되었는지, 외부적으로 저장되었는지, 저장 오류가 있었는지 파악
  3. 차이 파일이 캐시 가능한 경우(텍스트 기반), Gitlab::Diff::FileCollection::MergeRequestDiff을 사용하여 Redis에 캐시합니다.

차이 사항 주의

차이 사항에 대해 논평할 때(비교가 어떤 경우에도), 우리는 실제 DiffNote와 관련된 NoteDiffFile에 차이 사항의 일부를 저장합니다. 따라서 파일의 차이를 필요로 할 때마다 저장소에 접근하는 대신 다음을 수행합니다.

  1. NoteDiffFile#diff가 저장되어 있는지 확인하고 사용
  2. 그렇지 않은 경우, 현재 MR(Merge Request) 리비전이라면, 저장된 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 kilobytes가 이미 렌더링되었다면 파일 차이가 접혀집니다(확장 가능).

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

50000개의 라인이 이미 렌더링되었다면 더 이상 파일이 렌더링되지 않습니다.

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

5메가바이트가 이미 렌더링되었다면 더 이상 파일이 렌더링되지 않습니다. 모든 수집 제한 매개변수는 Gitaly에 전송되어 적용됩니다. 즉, 제한이 초과된 후에는 Gitaly가 저장할 안전한 양의 데이터만 반환됩니다.

개별 차이 파일 제한

각 차이 파일에 영향을 미치는 제한 사항입니다. 파일 수, 라인 수 및 파일 크기가 고려됩니다.

확장 가능한 패치(접힌 상태)

패치의 경우 지정된 ApplicationSettings#diff_max_patch_bytes 값의 10%를 초과하면 패치가 접힙니다. 즉, 최대 허용 값이 100kb인 경우 10kb에 해당합니다. 패치 크기가 ApplicationSettings#diff_max_patch_bytes를 초과하지 않으면 차이는 저장되어 있고 확장 가능합니다.

이 명명 방식(접힘)은 Gitaly에서도 사용되지만 이 제한은 GitLab에서만 사용됩니다(하드코딩되어 Gitaly로 전송되지 않음). 콜렉션 제한을 초과할 때 Gitaly는 Diff.Collapsed를 반환합니다.

확장 가능한 패치가 아님(너무 큼)

ApplicationSettings#diff_max_patch_bytes보다 큰 경우에는 패치가 렌더링되지 않습니다. 사용자들은 Changes are too large to be shown. 메시지를 보고 해당 커밋의 파일만 볼 수 있는 버튼을 볼 수 있습니다.

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

파일 차이가 5000줄보다 많은 경우에는 파일 차이가 억제됩니다(기술적으로 축소된 것과 다르지만 동일하게 작동하며 확장 가능함). 이 한계는 코드화되어 있으며 GitLab에서만 적용됩니다.

뷰어들

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

DiffViewer::Base블롭(이전 및 새 버전), 확장자 및 파일 유형을 유효성 검사하여 렌더링할 수 있는지 확인합니다.

대상 브랜치의 HEAD에 대한 병합 요청 차이점

과거에는 병합 요청 차이점이 git diff target...source에 의해 계산되었는데, 이는 대상 브랜치의 HEAD를 소스 브랜치의 병합 베이스(또는 공통 조상)와 소스 브랜치의 사이의 변경과 비교합니다. 이 방법은 대상 브랜치가 소스 브랜치에서 도입된 일부 변경을 포함하게 되면 잘 작동합니다. 다음 경우를 고려해 보세요. 여기서 소스 브랜치는 feature_a이고 대상은 main입니다:

  1. main에서 feature_a로 새 브랜치 feature_a를 확인하고 거기에서 file_afile_b를 제거합니다.
  2. mainfile_a를 제거하는 커밋을 추가합니다.

병합 요청의 차이점은 여전히 file_a 제거를 포함하고 있지만 실제 차이는 mainHEAD와 비교했을 때 file_b의 제거만 있습니다. 이 같은 중복 변경으로 인한 차이점은 리뷰하기 어렵습니다.

최신 차이점을 표시하기 위해 우리는 병합 요청 차이점을 대상 브랜치의 HEAD와 비교하도록 소개했습니다: 대상 브랜치가 소스 브랜치에 인위적으로 병합되고, 그 결과로 나온 병합 참조가 소스 브랜치와 비교되어 정확한 차이점을 계산합니다.

우리가 에픽 “병합 참조를 사용하여 차이점”“차이점에서 병합 충돌”을 완료할 때까지, main (base)main (HEAD) 옵션을 모두 병합 요청에 표시할 수 있습니다.

병합 참조 헤드 옵션

main (HEAD) 옵션은 나중에 main (base)을 대체하도록 의도되어 있습니다.

두 옵션에 대한 주석을 지원하기 위해 차이점 노트 위치는 main (base)main (HEAD) 버전에 대해 저장됩니다(소개됨 in 12.10). main (base) 버전의 위치는 Note#positionNote#original_position 열에 저장되고, main (HEAD) 버전의 위치에는 DiffNotePosition이 도입되었습니다.

병합 참조 차이점을 다룰 때의 주요 과제 중 하나는 병합 충돌입니다. 대상 및 소스 브랜치에 병합 충돌이 있는 경우, 이러한 브랜치는 자동으로 병합할 수 없습니다. 유튜브에서 재생 는 문제와 에픽을 모티브에 대한 간단한 소개입니다. 13.5에서 두 번 수정된 병합 충돌에 대한 솔루션이 소개되었지만, 앞으로 처리될 병합 충돌에 대한 더 많은 유형이 있습니다.