익숙한 습관과 깃
기획자가 깃에 대해 불평하기에 이어 또 깃에 대한 넋두리를 시작하겠습니다. 이전 몇 프로젝트에 퍼포스를 사용하다가 이번에는 깃을 사용하면서 여러 불만이 생겼는데요. 온라인에서 깃을 사용하는 엔지니어분들을 보면 별 문제 없이 잘 동작하는 것 같아 보여 부끄러운 기분이 들었습니다. 큰 규모 개발에서 또 깃을 언제 사용해볼 기회가 있을까 싶어 처음엔 기뻐했는데 비 엔지니어 입장에서는 이해가 쉽지 않은 이상한 동작으로 가득했습니다.
짧게 짚고 넘어가면 모든 직군에게 커밋과 푸시를 설명해야 했습니다. 깃은 분산환경으로 서로의 브랜치가 중앙에 통합되며 일어나는 온갖 사고를 회피하기 위해 작업환경을 로컬과 리모트로 구분했다고 이해했습니다. 그런데 게임 개발에서는 코드 이외의 바이너리 에셋이 많고 이들은 로컬과 리모트를 구분해서 관리할 이유가 별로 없습니다. 내 로컬에서 방금 편집한 레벨 에셋은 형상관리시스템에 등록함과 동시에 다른 사람들에게 공유 되어야 합니다. 내 로컬에만 커밋된 상태를 유지할 이유가 거의 없습니다. 사람들은 이전 습관대로 커밋 한 다음 확인해 달라고 메시지를 보내 왔는데 풀 해봐도 아무 것도 받지 않는 상황이 자주 일어납니다. 깃 비주얼 클라이언트에 충돌하지 않으면 커밋을 바로 푸시하는 체크박스가 있어 상황을 완화할 수는 있었지만 아무때나 울리는 화재경보기 전원을 뽑아 놓는 조치 같아 이를 설명하면서 불편한 감정을 느꼈습니다.
코드를 제외한 거의 모든 에셋을 머지할 수 없는 환경을 고려하지 않은 것 같아 보입니다. 그나마 기획 데이터는 어느 정도 기술적으로, 전략적으로 머지 가능해진 경우가 있기도 하지만 여전히 작업 방식을 단순하게 유지하기 위해 머지가 필요해지는 지점은 에셋을 분리해 머지를 요구하지 않도록 합니다. 언리얼에디터에서 레벨이나 블루프린트나 위젯을 수정했는데 다른 작업과 충돌한 상황을 생각해봅시다. 이거 작업자들끼리 가위바위보 해서 이긴 사람 작업만 남길 수밖에 없습니다.
이런 문제를 줄이기 위해 svn이나 퍼포스에는 락 개념이 있습니다. 한 사람이 파일이나 경로를 체크아웃하면 다른 사람들은 체크아웃을 막아버립니다. 이런다고 바이너리 충돌이 없어지지는 않지만 상황을 줄일 수는 있었습니다. 일단 깃 비주얼 클라이언트에는 퍼포스의 락 개념이 없어 보입니다. 언리얼 에디터에서 깃을 연동하면 체크아웃 할 때 락 비슷한 상태를 만들어 주는 것 같긴 한데 커밋에도 락 상태가 풀리지 않아 의도하지 않게 다른 사람들의 작업을 가로막기도 합니다.
트러블슈팅 과정을 납득하기 어려웠습니다. 언리얼 기반에서 개발할 때 흔히 개발환경을 열어둔 상태로 업데이트를 시도합니다. 에디터를 닫아도 에픽 크래시리포터가 한동안 떠서 dll이나 에셋을 잡고 있기도 하고요. 이 때 다른 형상관리도구에서는 그냥 업데이트를 재시도하면 되지만 깃은 내 입장에선 이상한 동작을 합니다. 현재 내 로컬 브랜치와 리모트 헤드 브랜치 사이에 변경된 모든 파일을 언스테이지 상태로 만들어 놓고 이걸 직접 제거하기를 요구합니다. 언스테이지에 올라간 파일은 어떤 형태로든 ‘변경된’ 파일이라고 생각했는데 풀에 실패했을 뿐인데도 파일이 변경되었다고 주장하는 동작은 납득하기 어려웠습니다. 이 상태의 트러블슈팅을 여러 직군에 안내하기는 더더욱 어려웠습니다. 누군가는 svn의 cleanup
이나 퍼포스의 force download
같은 건 없냐고 물었는데 허구헌날 스스로 생성한 인덱스나 락 파일을 어떻게 하지 못해 그냥 배째라 드러누워버리는 깃을 생각하니 뭐라 할 말이 없었습니다.
시작이 너무 길어졌는데 이런 경험 외에도 최근에 겪은 이상한 상황은 작업자들끼리 ‘어느 지점’까지 받은 다음 실행해 달라고 의사소통을 할 수 없었다는 점입니다. 퍼포스는 리소스 트리 전체를 단일 복사본으로 중앙에서 관리하며 체크아웃과 서브밋을 경로 단위로 하고 또 각 서브밋은 리비전 번호 모양으로 나타납니다. 그래서 리소스를 업데이트 할 때는 ‘특정 경로를 업데이트 하라’ 또는 ‘특정 경로를 특정 리비전 까지 업데이트 하라’는 식으로 의사소통을 할 수 있습니다.
깃에서는 일단 같은 브랜치의 특정 경로만 최신화 할 방법이 없어 보입니다. 일단 풀 하면 리모트 헤드에 도달할 때까지 트리 전체의 변경사항을 다 받아버립니다. 레벨디자이너가 커밋 두 개를 풀 했는데 이 중 더 이른 시점의 커밋만을 우선 공유해 테스트하기를 원한다면 이전에는 특정 경로와 리비전 번호, 또는 그냥 리비전 번호를 사용해 의사소통 할 수 있었지만 깃에서는 SHA 해시를 공유해야 합니다. SHA 해시는 일단 사람이 읽을 수가 없습니다. 앞쪽이나 뒤쪽 몇 글자만 주고받는 것도 쉽지 않고요. 나토 음성 문자로 불러주게 생겼습니다. 또 SHA 해시는 이것만 가지고는 전후 관계를 파악할 수가 없습니다. 그래서 지금 내가 들은 해시가 두 커밋 중 앞쪽일까 뒤쪽일까를 고민해야 했습니다.
깃에서는 근본적으로 깃에 맞는 개발 시나리오가 있을 겁니다. 게임 개발팀은 엔지니어가 아닌 직군이 많이 포함되어 있어 이들 전체에 적용할 개발 시나리오를 개발해 교육하고 지속적으로 관리해야 합니다. 사실 처음엔 도대체 깃은 왜 비 엔지니어에게 이렇게 적대적인가 하는 생각을 했는데 최근에는 깃에 맞는 개발 시나리오를 생각해 보고 있습니다. 가령 ‘특정 경로 하위에 있는 파일’ 단위로만 작업을 공유하고 싶다면 브랜치를 만들어 관리해야 하는 식으로요. 하지만 이런 시나리오를 생각하면서도 이걸 모든 직군에게 교육할 수 있기는 한 건지 스스로 의심스럽습니다.