github로 유니티 프로젝트를 공유하면 머티리얼이 빠지는 이유: .meta 파일
팀원이 github에서 유니티 프로젝트를 받아 열었더니 오브젝트의 머티리얼이 빠져 있습니다. 씬에 놓아 둔 프리팹은 Missing으로 뜹니다. 그런데 Assets 폴더를 열어 보면 머티리얼 파일도, 텍스처도, 프리팹도 다 있습니다. 파일은 다 있는데 유니티만 그 파일을 못 찾는 상황입니다.
급한 마음에 Inspector에서 머티리얼을 하나씩 다시 끼워 넣는 사람이 많습니다. 오브젝트 몇 개라면 그걸로 끝납니다. 하지만 프리팹이 수십 개라면 어떨까요? 다시 끼우지 않고 한 번에 되돌리는 길이 있습니다. 그 열쇠는 4절에서 꺼냅니다. 이 글은 다섯 가지를 차례로 짚습니다. 기준은 Unity 6 매뉴얼이고, git 동작은 git 2.38에서 같은 파일 구조를 만들어 돌려 본 결과입니다.
- 1. 유니티는 파일 이름이 아니라 GUID로 찾습니다
- 2. github에서 .meta가 빠지거나 바뀌는 세 갈래
- 3. 미리 지키는 설정과 점검
- 4. 이미 끊겼다면: 옛 GUID를 되살리기
- 5. pull이 막히거나 .meta가 충돌할 때
1. 유니티는 파일 이름이 아니라 GUID로 찾습니다
마야를 써 봤다면 비슷한 일을 겪어 봤을 겁니다. 씬을 다른 PC에서 열면 텍스처가 사라지는 일입니다. 마야는 텍스처를 파일 경로로 기억합니다. 그래서 경로가 달라지면 연결이 끊깁니다.
유니티는 반대 방식을 씁니다. 에셋을 Assets 폴더에 넣으면 유니티가 그 에셋에 고유한 ID를 붙입니다. 그리고 같은 자리에 이름 끝에 .meta가 붙은 파일을 하나 만들어 그 ID를 적어 둡니다. 이 ID를 GUID라고 부릅니다. Unity 6 매뉴얼은 이 ID 덕분에 에셋을 옮기거나 이름을 바꿔도 아무것도 깨지지 않는다고 설명합니다. .meta에는 GUID 말고도 그 에셋의 임포트 설정이 함께 들어 있습니다.
Brick.mat.meta
fileFormatVersion: 2
guid: 2222bbbb2222bbbb2222bbbb2222bbbb
Wall.prefab (이 머티리얼을 쓰는 프리팹)
m_Materials:
- {fileID: 2100000, guid: 2222bbbb2222bbbb2222bbbb2222bbbb, type: 2}
프리팹과 씬은 머티리얼을 이름으로 적지 않습니다. 위처럼 guid 값으로 적습니다. 매뉴얼의 씬 파일 예시에도 MeshRenderer의 m_Materials가 이 형태로 들어 있습니다. 텍스처를 쓰는 머티리얼, 프리팹을 놓은 씬도 모두 같은 방식으로 상대를 가리킵니다.
그럼 .meta가 없는 에셋이 팀원 PC에 도착하면 어떻게 될까요? 매뉴얼에 답이 있습니다. 유니티는 그 에셋을 처음 보는 새 에셋으로 여기고 새 .meta를 만듭니다. 새 .meta에는 새 GUID가 들어갑니다. 프리팹은 여전히 옛 GUID를 찾습니다. 매뉴얼은 텍스처가 .meta를 잃으면 그 텍스처를 쓰던 머티리얼이 연결을 잃고, 스크립트가 .meta를 잃으면 게임오브젝트와 프리팹에서 스크립트가 빠진다고 적습니다. 머티리얼과 프리팹도 같은 원리로 빠집니다.
파일이 그대로 있어도 GUID가 다르면 유니티에게는 다른 에셋입니다.

그렇다면 .meta는 어디서 빠지거나 바뀔까요? github를 거치는 길에 갈림길이 세 군데 있습니다.
2. github에서 .meta가 빠지거나 바뀌는 세 갈래
| 갈래 | 생기는 일 | 알아보는 법 |
|---|---|---|
| .gitignore에 *.meta를 넣음 | 무시 규칙에 걸린, 아직 Git이 추적하지 않는 .meta는 github에 올라가지 않습니다. 이미 추적 중인 .meta는 무시 규칙을 추가해도 계속 관리됩니다. 짝 .meta가 빠진 에셋은 팀원 PC에서 새 GUID를 받을 수 있습니다 | GitHub에서 새로 추가한 에셋 옆에 같은 이름의 .meta가 없는지 확인합니다 |
| 에셋만 커밋하고 .meta를 빼먹음 | 새로 넣은 에셋 몇 개만 팀원 쪽에서 새 GUID를 받습니다 | GitHub Desktop의 Changes 목록에 .meta가 남아 있습니다 |
| 팀원 PC에서 새로 생긴 .meta를 커밋함 | 원래 GUID가 새 GUID로 덮여 내 PC까지 참조가 끊깁니다 | .meta 변경 내역에서 guid 줄이 바뀌어 있습니다 |
첫째 갈래는 용량을 줄이려다 생깁니다. Unity 프로젝트를 올리면 용량이 너무 크니 .gitignore에 *.png, *.fbx와 함께 *.meta를 넣으라는 글이 실제로 돌아다닙니다. GitHub의 공식 Unity.gitignore 템플릿은 *.meta 전체를 빼지 않습니다. 디버그용 파일에 붙는 *.pdb.meta 같은 몇 줄만 뺍니다. 같은 구조를 만들어 *.meta 줄을 넣어 보니 git status에 .meta가 하나도 뜨지 않았습니다. 커밋에는 에셋만 들어갔습니다. 내 PC에는 .meta가 남아 있으니 내 쪽은 멀쩡합니다. 그래서 팀원이 받기 전까지는 아무도 모릅니다.
둘째 갈래는 GitHub Desktop(깃허브 데스크탑)에서 자주 나옵니다. Changes 목록에서 바꾼 파일만 골라 체크하다 보면 옆에 붙은 .meta를 놓치기 쉽습니다. 새 텍스처를 넣었다면 Changes에는 텍스처와 그 .meta가 둘 다 떠야 합니다. 폴더를 새로 만들었다면 폴더 이름의 .meta도 하나 더 뜹니다.
셋째 갈래가 가장 고약합니다. 팀원 PC의 유니티는 .meta가 없는 에셋을 보고 새 .meta를 만듭니다. 팀원이 그 상태로 Changes에 뜬 .meta를 모두 커밋하면 어떻게 될까요? 새 GUID가 github에 올라가고, 내가 pull하는 순간 내 .meta까지 새 GUID로 바뀝니다. 실험에서도 .meta의 guid 줄 하나가 바뀐 커밋이 그대로 올라갔습니다. 이제 내 PC에서도 프리팹이 머티리얼을 못 찾습니다. 팀원 PC에서 새로 생긴 .meta는 커밋하지 않습니다.
github 밖에서도 같은 일이 생깁니다. 매뉴얼은 유니티의 Project 창 안에서 에셋을 옮기거나 이름을 바꾸면 .meta도 함께 따라간다고 적습니다. 탐색기에서 직접 옮기면 .meta는 제자리에 남습니다. 그래서 탐색기에서 옮길 때는 .meta도 함께 옮겨야 합니다.
3. 미리 지키는 설정과 점검
먼저 유니티 설정 두 곳을 봅니다. Unity 6에서는 둘 다 기본값이 맞게 되어 있습니다. 예전 프로젝트를 이어 쓰거나 누군가 바꿨을 수 있으니 한 번 확인합니다.
| 위치 | 맞는 값 | 이유 |
|---|---|---|
| Edit > Project Settings > Version Control > Mode | Visible Meta Files | git처럼 유니티가 직접 연동하지 않는 버전 관리를 쓸 때 고르는 값입니다. Hidden Meta Files는 탐색기에서 .meta를 숨깁니다 |
| Edit > Project Settings > Editor > Asset Serialization > Mode | Force Text | 씬·프리팹·머티리얼이 글자로 저장됩니다. 4절처럼 GUID를 검색해 되살릴 수 있습니다 |
다음은 .gitignore입니다. 아래 명령은 지정한 경로가 무시 규칙에 걸리는지 확인합니다. –no-index를 붙이면 Git이 이미 추적 중인 파일도 규칙 검사에 포함합니다. 아무것도 나오지 않으면 해당 경로는 무시 규칙에 걸리지 않은 것입니다. 줄이 하나 나오면 표시된 파일의 해당 줄이 그 경로를 무시하고 있다는 뜻입니다. 실험에서는 .gitignore:2:*.meta가 나왔습니다. 그 줄을 지우고 나니 Changes에 .meta 8개가 새 파일로 떴습니다.
git check-ignore -v --no-index Assets/Materials/Brick.mat.meta
마지막은 짝 맞추기입니다. 로컬 저장소에서 Git이 추적 중인 Assets 파일 중 .meta 짝이 없는 에셋을 찾는 PowerShell 명령입니다. PowerShell을 열고 cd 명령으로 Assets 폴더가 보이는 프로젝트 폴더로 옮겨 가서 실행합니다. git 명령을 찾을 수 없다고 나오면 Git for Windows를 먼저 설치합니다. 출력이 비어 있으면 로컬에서 Git이 추적 중인 파일은 모두 짝을 갖춘 것입니다. GitHub 원격에도 반영됐는지는 push 뒤 웹에서 확인합니다. 실험에서 .meta 없이 커밋한 wood.png가 이 명령에 걸렸습니다.
$f = git ls-files Assets
$f | Where-Object { $_ -notlike '*.meta' -and ($f -notcontains "$_.meta") }
여기까지는 미리 막는 법입니다. 그럼 팀원 PC에서 이미 머티리얼이 빠졌다면, 하나씩 다시 끼우는 것 말고 무엇이 남았을까요?
4. 이미 끊겼다면: 옛 GUID를 되살리기
1절의 코드를 다시 떠올려 봅니다. 프리팹 파일 안에는 옛 GUID가 아직 그대로 적혀 있었습니다. 끊긴 것은 프리팹이 아니라 머티리얼 쪽 .meta입니다. 그러니 머티리얼을 다시 끼울 필요가 없습니다. 씬·프리팹에 옛 GUID가 남아 있다면, 머티리얼의 .meta에 그 GUID를 돌려 넣어 참조가 되살아날 수 있습니다. Unity를 다시 열어 실제로 복구됐는지 확인합니다.
참조가 끊긴 원인이 .meta의 GUID 변경이라면, 옛 GUID를 복원해 여러 참조를 한 번에 되살릴 수 있습니다.
옛 GUID가 어디 남아 있느냐에 따라 길이 셋으로 나뉩니다. 어느 길이든 먼저 Unity를 닫고 프로젝트 폴더를 통째로 복사해 둡니다. Unity가 열린 채로는 .meta가 없는 에셋에 새 .meta를 만들 수 있기 때문입니다. 끊긴 상태의 씬과 프리팹은 저장하지 않습니다.

원래 .meta가 아예 안 올라갔을 때
.gitignore에 *.meta가 있었던 경우입니다. 원래 GUID를 담은 .meta는 원본 프로젝트 복사본이나 백업 등에 남아 있을 수 있으니 확인합니다. 그래서 .meta는 원래 프로젝트를 만든 PC에서 올립니다. 그 PC에서 .gitignore의 *.meta 줄을 지우고, Changes에 뜬 .meta를 모두 커밋해 push합니다. 팀원은 새로 생긴 자기 .meta를 커밋하지 말고 Unity를 닫은 채 pull합니다.
실험에서는 팀원 쪽 .gitignore도 *.meta를 무시하던 상태라, pull 한 번에 팀원 PC의 새 .meta가 원래 .meta로 덮였습니다. git은 무시하던 파일을 덮어쓰는 것을 막지 않기 때문입니다. 팀원 쪽에서 .meta가 이미 새 파일로 떠 있었다면 5절의 오류가 납니다.
한때 올라갔다가 새 GUID로 바뀌었을 때
2절의 셋째 갈래입니다. 옛 GUID는 git 기록에 남아 있습니다. 먼저 끊긴 프리팹이 찾는 GUID를 확인합니다. 프리팹이나 씬 파일을 메모장으로 열어 m_Materials 줄의 guid 값을 복사합니다. 그 값으로 기록을 검색합니다.
git log --oneline -S2222bbbb2222bbbb2222bbbb2222bbbb -- "*.meta"
7fe67d3 teammate commit (meta regenerated) ← 이 GUID를 지운 커밋
3c44e90 add meta files ← 이 GUID를 처음 넣은 커밋
git restore --source=7fe67d3~1 -- Assets/Materials/Brick.mat.meta
-S는 그 글자가 생기거나 사라진 커밋을 찾습니다. 맨 위가 GUID를 지운 커밋입니다. 그 커밋 바로 앞(~1)의 .meta를 꺼내면 옛 GUID가 돌아옵니다. 실험에서도 guid 줄이 2222로 시작하는 원래 값으로 돌아왔습니다. 이것을 커밋해 push하고 Unity를 엽니다.
어디에도 원래 .meta가 없을 때
기록에도, 원래 만든 사람의 PC에도 없다면 GUID를 손으로 맞춥니다. 프리팹이나 씬 파일에서 찾은 옛 GUID를 복사합니다. 그다음 머티리얼의 새 .meta를 메모장으로 열어 guid: 뒤의 값을 옛 GUID로 바꿉니다. 바꾸기 전에 그 GUID를 쓰는 다른 .meta가 프로젝트 안에 없는지 git grep으로 먼저 찾아봅니다. 끊긴 에셋이 몇 개뿐이고 어떤 머티리얼이었는지 확실하다면, Inspector에서 다시 끼우는 편이 더 빠릅니다.
5. pull이 막히거나 .meta가 충돌할 때
.meta를 바로잡는 도중에 git이 두 가지 메시지로 멈출 수 있습니다. 둘 다 같은 질문으로 풉니다. 이미 다른 파일들이 가리키고 있는 GUID가 어느 쪽인가입니다.
untracked working tree files would be overwritten
내 PC의 유니티가 만든 .meta가 아직 커밋 안 된 새 파일로 남아 있을 때, 같은 이름의 .meta를 pull하면 나는 오류입니다. 실험에서는 아래처럼 멈췄습니다.
error: The following untracked working tree files would be overwritten by merge:
Assets/Textures/wood.png.meta
Please move or remove them before you merge.
Aborting
내 쪽 .meta는 내 유니티가 방금 만든 새 GUID입니다. 받으려는 쪽이 원래 GUID입니다. Unity를 닫고 목록에 나온 내 .meta를 지운 뒤 다시 pull합니다. 실험에서도 지운 뒤 pull하자 원래 GUID가 든 .meta가 내려왔습니다.
CONFLICT (add/add)가 .meta에 났을 때
두 사람이 같은 텍스처를 각자 Assets에 넣고 따로 커밋하면 생깁니다. 실험에서는 텍스처 파일 내용이 같아 텍스처는 충돌하지 않았습니다. .meta만 CONFLICT (add/add)로 멈췄습니다. 두 .meta의 GUID가 서로 달랐기 때문입니다.

남길 쪽은 이미 다른 파일들이 가리키는 GUID입니다. 두 GUID를 각각 git grep으로 검색해 보면 어느 쪽을 머티리얼과 프리팹이 쓰고 있는지 바로 보입니다. 보통은 먼저 push된 쪽입니다. pull 중에 난 충돌이라면 –theirs가 github에서 받아 온 쪽, –ours가 내 쪽입니다. pull을 rebase 방식으로 설정해 두었다면 둘이 반대입니다.
git grep -n aaaa0000aaaa0000aaaa0000aaaa0000
git checkout --theirs -- Assets/Textures/stone.png.meta
git add Assets/Textures/stone.png.meta
git commit
버린 쪽 GUID로 이미 연결한 머티리얼이 내 PC에 있었다면 그 연결은 끊깁니다. 그 몇 개만 Inspector에서 다시 끼웁니다.
제대로 이어졌는지 확인하기
- GitHub 웹에서 짝 보기: 저장소의 Assets 안 아무 폴더나 열어 봅니다. 파일마다 같은 이름에 .meta가 붙은 파일이 하나씩 나란히 있어야 합니다.
- 짝 없는 파일 검사: 3절의 PowerShell 명령 출력이 비어 있어야 합니다.
- 팀원 입장에서 받아 보기: 빈 폴더에 저장소를 clone하고 Unity Hub에서 엽니다. 연 뒤 GitHub Desktop의 Changes에 새 .meta가 뜨면 GitHub에 짝 파일이 없을 수 있습니다. 다만 .gitignore가 .meta를 무시하면 Changes에 안 뜨므로, 앞의 git check-ignore 검사와 GitHub 웹의 파일 목록도 함께 확인합니다.
- 씬 열어 보기: Hierarchy에 Missing Prefab으로 시작하는 오브젝트가 없고, 오브젝트를 골랐을 때 Inspector의 머티리얼 칸에 Missing이 없으면 끝입니다.
매뉴얼의 .meta 설명 원문은 아래에서 볼 수 있습니다. 탐색기에서 옮길 때의 주의, 빈 폴더와 .meta의 관계도 함께 나와 있습니다.
같은 증상이 유니티가 아니라 마야 씬에서 났다면 원인이 반대입니다. 그때는 마야 씬을 다른 PC에서 열 때 텍스처 경로 확인하기부터 봅니다.
한 줄 정리
유니티는 파일 이름이 아니라 .meta 속 GUID로 찾습니다. 에셋은 .meta와 한 쌍으로 올리고, 끊기면 옛 GUID를 되살립니다.
vfx 잡학지식


댓글 0
첫 댓글을 남겨보세요.