대용량 파일이 있는 유니티 프로젝트를 어떻게 버전 컨트롤로 관리하나

https://www.reddit.com/r/Unity3D/comments/19a6o8i/how_to_version_control_large_projects_with_big/

 

해당 글에 따르면, Git LFS 사용 또는 PlasticSCM 사용을 권장하는 사람이 많이 보인다. Git을 사용한다면 게임 리포지토리는 정말 커질 수 있기에 꼭 필요한 것만 저장소에 보관하는 것이 좋다고 한다. 예를 들어 에셋 팩에서 에셋을 가져올 때는 프로젝트에 실제로 필요한 것만 가져와야 한다.

 

LFS를 사용할 예정이라면, 모든 바이너리 파일 형식(이미지, 모델, 바이너리, 오디오 등)을 캡처할 수 있도록 LFS 속성을 제대로 설정하는 것이 중요하다. 

 

그럼 Git LFS의 비용은?

https://docs.github.com/ko/billing/managing-billing-for-git-large-file-storage/about-billing-for-git-large-file-storage

 

공식 깃헙에 따르면 무료 스토리지 1GB, 매월 무료 대역폭 1GB를 제공받는다고 한다. 이 이상 사용하려면 추가 할당량을 구매해야 한다고. 또한 대역폭 및 스토리지 사용량은 레포지토리 단위가 아닌, 소유자 계정에 대해서 계산이 된다. 포크된 레포에서는 레포제토리 네트워크의 루트에 대해 계산된다고 한다. 이런 협업 및 포크 레포지토레에 대한 사용자는 스토리지 및 대역폭 할당량에 영향을 받지 않는 것처럼 보여 데이터 팩을 구입하지 않고도 푸시할 수 있다고 한다. 모두 부모 리포지토리에 대해 사용량이 계산되는 형태이다.

 

추가 용량 및 대역폭을 구매하려면 데이터 팩을 구매하면 되는데, 데이터 팩 1개는 매월 5달러이며 월별 할당량으로 50GB대역폭과 50GB 스토리지를 제공한다고 한다. 즉, 1GB이상 50GB 이하의 프로젝트는 6.666원 정도 가량을 월마다 내고 유지시켜야 한다.

 

 

 

 


 

 

Git으로 유니티 프로젝트 설정

https://www.diversion.dev/blog/how-to-version-your-unity-project-with-git

 

Git과 같은 버전 컨트롤에서는 관련 파일과 무시해야 할 파일을 올바르게 지정하는 방법을 이해하는 것이 중요하다.

 

 

.gitignore의 설정 방법

Git에서 실제로 버전 관리 파일의 양을 줄이기 위해 Unity 프로젝트 계층구조 관련으로 좋은 방법들이 있다고 한다. 대부분의 Git 리포지토리가 그렇듯이 .gitignore 파일을 통해 툴이 데이터 손실 없이 안전하게 무시할 수 있는 파일이나 폴더를 적절히 알려주는 것이 중요하다. Unity의 경우 .gitignore 파일에는 일반적으로 최소한 다음이 포함된다.

  • /[Ll]ibrary/: 운이 좋게도, 유니티의 프로젝트는 직접적으로 모든 디펜던시를 포함하지 않아도 된다. 버전 관리를 위해 단지 manifest.json과 packages-lock.json파일을 포함하고 있는 Packages/ 폴더만 공유하면 된다. 이 파일들은 모든 필수 lib 종속성을 자세히 설명하는 간단한 메타 데이터 목록으로, 다른 유니티 인스턴스가 올바른 올바른 버전에서 필요한 모든 패키지를 검색할 수 있도록 하게 해준다.
    • manifest.json을 편집하면 이를 통해 패키지를 설치할 수도 있다. 방법
    • package-lock.json 설명 공식 문서. 수동으로 수정하지 말고, 종속성 버전을 새로 고치려면 삭제하라고 한다. 그럼 아마 새로 생성해줄 듯. 유니티가 소스 컨트롤에서 관리하라고 권장.
    • https://discussions.unity.com/t/packages-lock-json/795947 해당 글에 따르면, Unity 2020 버전 이상부터 git url을 통해 Packges/manifest.json에 추가된 커스텀 패키지는 이전처럼 해시 같은 lock information을 manifest.json에 추가하지 않고, Packages/packges-lock.json에 추가한다고 한다. 그래서 버전 관리 시스템에 해당 파일도 추가 필요.

manifest.json, packages-lock.json

  • /[Oo]bj/, /[Bb]uild/, /[Bb]uilds/…: 컴파일 중 또는 런타임에 Unity에서 자동 생성된 모든 파일은 다른 Unity 인스턴스가 필요할 때 다시 생성하므로 당연히 무시해도 된다.
  • *.tmp, /[Tt]emp/ and /[Ll]ogs/: 이런 임시 파일은 작업 세션(유니티를 시작할 때 동적으로 생성되며 닫을 때는 자동으로 삭제된다. 이는 프로젝트를 여는 장치에 따라 달라진다.)과 관련이 있으므로 당연히 무시가능하다.
  • /[Rr]ecordings/ and /[Mm]emoryCaptures/: 이러한 파일은 크기를 급격하게 증가시켜 스토리지 사용양을 증가시킬 수 있으며, 민감한 데이터를 포함할 수 있다.

전체 예제 .gitignore를 얻으려면 다음과 같이 구할 수 있다.

  1. 공식 샘플을 얻기
  2. Github, Gitlab 레포지토리를 생성할 때 ignore 설정을 선택하

물론 유니티 프로젝트에서 퍼블리싱을 하기 위한 Apple Store나 Goole Play 키의 자격 증명 정보를 가지고 있다면 이또한 반드시 .gitignore에 추가해야 한다. 새 커밋으로 이러한 파일을 제거해도 레포지토리 기록이 지워지지 않으니 조심해야 한다.

 

유니티 에디터 세팅

https://docs.unity3d.com/kr/2022.3/Manual/class-EditorManager.html

게임 프로젝트는 단순히 코드 스니펫과 에셋을 한데 모아 놓은 것이 아니라, 모든 데이터를 올바른 방식으로 연결하고 참조해야만 예쌍한 상호작용과 실제 플레이가 가능한 결과를 얻을 수 있다는 점이 중요하다.

 

유니티 프로젝트에서 데이터의 연결과 참조는 .meta파일로 처리되며, 에디터는 프로젝트의 모든 폴더와 파일에 대해 메타 파일을 자동으로 생성한다. 보통 데이터 외부에서 게임 프로젝트의 계층 구조를 살펴보면 .meta파일이 보이지 않는다. 마찬가지로 Git에서도 보이지 않기에 visible meta file 설정을 만져준다.

 

Visible Meta File 설정

https://docs.unity3d.com/kr/2022.3/Manual/class-EditorManager.html

Project Settings/Version Contorl의 Visible Meta File 설정 예시 이미지

Verson Control 항목에서 확인할 수 있는데, 이를 통해 메타 파일을 표시 또는 숨기기를 할 수 있다. 원래는 Hidden Meta Files이 디폴트라고 하지만, 버전 관리 시 메타 파일을 표시하는 것이 편하기에 이를 세팅해준다.

 

 

 

에셋 직렬화 방식 설정

직렬화된 에셋을 저장하는데 사용할 포맷을 의미한다. 기본적으론 Force Text로 설정된다. 유니티는 직렬화를 사용하여 에셋과 에셋 번들을 컴퓨터 HDD에 로드하고 저장한다. Force Text는 모든 에셋을 텍스트 모드로 전환하는데, 깃으로 관리할 떄는 Force Text 그대로 사용하면 된다.

*Serialization은 객체(오브젝트)의 상태를 저장하거나 전송하기 위해 데이터 구조나 오브젝트 상태를 일련의 바이트 혹은 문자로 변환하는 과정이다.

Project Settings/Editor의 직렬화 방식 설정

 

 

 


 

용량이 큰 파일들의 적절한 관리법

파일이 필요 이상으로 커서는 안되기에, 적절한 형식과 해상도를 선택하여 파일 크기를 크게 줄여 스토리지 사용량을 개선해야 한다. 이미지의 경우 특히 중요하다.

 

물론 다양한 플랫픔과 화면 크기를 수용하고 싶겠지만, 프로젝트의 모든 이미지를 4K에 맞춰 준비할 필요가 없다. 따라서 좋은 프로세스는 높은 해상도의 원본 파일은 버전 컨트롤 밖의 다른 곳에 저장해두고 최종 에셋만 버전 관리에 포함하면서 프로젝트의 요구 사항에 맞게 내보도록 하는 것이다. 

 

주어진 이미지 크기가 내 게임에서 동작하는지 확인하기 위해 실제로 가능한 테스트 법은 유니티에서 임포트 시 이미지 에셋에 대해 최대 해상도를 설정하는 것이다. 이를 유니티에서 테스트해볼 수 있다.

 

해당 임포트 설정은 이미지 파일 자체를 수정하는 것이 아니라 Unity내에서 최대 해상도를 제한하는 것이므로 이미지가 여전히 게임에서 읽을 수 있는 해상도를 확인한 다음 익스포트에 해당 설정을 다시 적용하여 실제로 파일 크기를 줄일 수 있다.

 

 

복제 대신 재사용하기

에셋의 변형을 예상하고 이 파일을 반복해서 복제하지 않고도, 다른 대안으로 자동 변환할 수 있는 베이스를 생성하는 것도 좋은 방법이다. 

 

예를 들어, 플레이어 한 명당 작은 캐릭터 몇 명이 뛰어다니는 2D 플랫포머 게임이 있다면 각 아바타으 모양은 정확히 같지만 각 플레이어를 구분하기 위해 색상이 달라져야 한다. 이제 이러한 스프라이트가 모든 애니메이션과 포즈를 갖도록 스프라이트 시트에 정의되어 있다고 하면 플레리어당 하나의 스프라이트 시트를 준비하고 각각 색상을 변경하는 것이다.

 

이 문제점은 유지보수 측면에서 매우 불리하다. (한 스프라이트 시트의 청크를 변경하려면 아티스트가 다른 모든 스프라이트 시트를 동일한 방식으로 업데이트 해야하므로 오류가 발생하기 쉽다.) 스토리지 측면에서 전혀 효율적이지 않다. 따라서 더 나은 해결책은 컬러 스왑 셰이더를 사용하여 플레이어별 색상 변형을 만들고 그에 따라 스프라이트 시트의 색상 팔레트를 전환하는 것이다.

 

런타임에 머터리얼 프로퍼티 블록 인스턴스를 사용하여 커스터마이징할 수 있는 머터리얼, 피치를 변경하거나 잘게 잘라 다른 오디오 클립을 만들 수 있는 사운드, 결합하여 고유한 세트를 구성할 수 있는 3D 모델도 마찬가지이다.

 

 


 

 

깃 프로젝트 작업 방법

https://www.reddit.com/r/gamedev/comments/wgbv0x/how_do_you_handle_git_unity_projects_in_large/

  • 일반적인 씬 요소를 프리팹으로 분리하여 이러한 요소의 변경이 씬 에셋의 변경을 초래하지 않도록 해야한다. (잠재적인 병합 충돌이 발생하지 않도록)
  • Git의 Feature 브랜치에서 모든 변경 단위를 최대한 작게 유지해야한다. 브랜치가 병합되지 않은 상태로 오래 유지될수록 충돌 가능성이 높아진다.
  • Git의 도구 선택만큼 중요한 것은 작업을 어떻게 나누고 구성하는지도 중요하다. 모든 작업을 같은 씬, 같은 코드 모듈에서 하게 된다면 프로젝트 구조에 잘못접근했거나 코드 디자인 방식이 잘못된 것이다.
  • 이러한 것들을 제대로 이해하지 못하면 어떤 도구를 사용하던 병합 충돌이 발생할 수 있다.
  • 프리팹뿐만 아니라, additive loading을 통해 씬을 완전히 분할하는 것도 종종 합리적이다. 이 코드는 구현하는데 매우 짧은 시간이 걸리지만 충돌을 병합하는 데 놀라운 효과를 발휘할 수 있다.
  • 터레인, 플레이어, 적, npc, 상호작용 가능한 모든 것을 각각의 씬에 배치할 수 있다.
  • Feature 브랜치를 사용하되, 리뷰를 자주하고 아틀라시안에서 설명하듯이 2주 단위의 스프린트 리뷰가 있으면 좋다.
    • Feature 브랜치를 사용할 때 메이 브랜치에 병합하기 전 다른 개발자가 코드를 검증할 수 있도록 풀 리퀘스트를 반드시 활용한다고 한다.
    • 코드 검토가 완료될 때까지 develop 또는 master 브랜치와 병합을 금지해야한다고 한다.
    • Jenkins를 통합할 때도 모든 플랫폼의 모든 빌드가 정상적으로 작동할때까지 병합을 허용하지 않았다고 한다. 이렇게 하면 여러 플랫폼에 릴리즈 할 때 골치 아픈일을 줄일 수 있다.
  • 자주 병합하고, 아무도 동시에 같은 Scene파일에서 작업하지 않도록 하는 방법을 찾아야 한다고 한다.
  • 다른 사람과 동일한 프리팹에서도 작업하지 말고, 동일한 텍스처/모델에서 작업하지 말라고 한다. 코드 파일은 병합해도 괜찮다고 한다. 변경 사항을 병합하기 쉽도록 작게 만드는게 좋음. 각 작업에 대해 최대 1~3일 길이의 작업을 만들고 각 작업을 병합하면 좋다.
  • 어쩄든 씬을 편집하지 말라고 한다. 테스트 등을 위해 씬 편집이 필요한 경우 각 기여자가 각자의 씬에서 작업하도록 하라고 한다. 대규모 씬 편집을 깔끔하게 머지하는 것은 거의 불가능하다.
  • Git을 사용하려면 LFS에서 제공하는 파일 잠금을 사용하면 좋다고 한다.
  • https://learn.unity.com/tutorial/working-with-yamlmerge# YAML Merge라는게 있다고 하는데, 이것도 한 번 살펴보아야 한다.

 

 

 

 

 

참고자료