Merge시 자주 발생하는 이슈
1. 머지중 놓친 닫는 } → C2601의 원인
머지(특히 union/수동 해결)는 닫는 브레이스 하나를 놓칠 수 있음. C++은 함수가 안 닫히면 그 뒤 함수들을 전부 "앞 함수 안의 지역 함수"로 해석 → 엉뚱한 곳에서 에러가 터짐.
EnemyCombatComponent.cpp(805): error C2601:
'UEnemyCombatComponent::FindBestPattern': 지역 함수 정의가 잘못되었습니다.
... 이후 모든 에러가 'UEnemyCombatComponent::ApplyHitToActor::...' 스코프로 폭발
진단법
- 에러가 난 함수(FindBestPattern)가 범인이 아님. 에러 스코프 prefix(
ApplyHitToActor::)가 안 닫힌 함수를 가리킴. - 그 함수 구간의 여는
{vs 닫는}개수를 셈 → 15 vs 14, 1개 누락 확정.
덤으로 드러난 로직 버그
브레이스만 문제가 아니라, 우리 bCanBeParried 주입이 넉백 if 안에 잘못 중첩돼 있었음.
❌ 머지 결과 (패링이 넉백에 종속 + 닫는 } 증발)
if (KbCfg.bUseLaunchKnockback)
{
Spec.Data->SetSetByCallerMagnitude(...);
if (ActivePatternRow->bCanBeParried) // ← 넉백 꺼지면 패링 태그도 안 붙음
{
Spec.Data->AddDynamicAssetTag(Parryable);
}
} // ← 넉백 if를 닫는 } 가 사라져 함수가 안 닫힘
✅ 원본(origin/develop) 구조로 블록 복원
if (KbCfg.bUseLaunchKnockback)
{
Spec.Data->SetSetByCallerMagnitude(...);
}
if (ActivePatternRow->bCanBeParried) // 넉백과 독립된 형제
{
Spec.Data->AddDynamicAssetTag(Parryable);
}
주의: 머지 잔재는 들여쓰기(탭/공백)까지 뒤섞임. Edit의 공백-정확매칭이 계속 실패 → 라인번호 기반 치환(스크립트)으로 복구. 머지 깨진 구간은 공백 의존 편집이 위험.
2. Git LFS 바이너리 머지는 "한쪽 통째로"
.uasset은 LFS 포인터(130바이트 텍스트)로 추적됨. git diff/blob 해시는 실제 에셋이 아니라 포인터를 비교하는 것.
version https://git-lfs.github.com/spec/v1
oid sha256:dbf36ac803ae67b5...
size 29581
바이너리는 자동 3-way 머지 불가 → 머지는 항상 한쪽을 통째로 선택(pick-a-side). 우리 케이스는 양쪽 동시수정 5개가 전부 THEIRS로 해결 → 우리 기능 편집분이 HEAD에서 증발(커밋 8c0defed7에만 잔존).
진단 1 — 어느 쪽이 채택됐나 (oid 비교)
머지결과 oid == ours? == theirs? 비교로 확정.
진단 2 — 실질 변경 vs 재저장 잡음 (size 델타)
| 에셋 | base | ours | theirs | 해석 |
|---|---|---|---|---|
| BP_GA_Guard | 17227 | +1003 | +5 | 우리=기능 / 그들=잡음 |
| DT_SkillCombination | 19818 | +8056 | +93 | 우리=기능 / 그들=잡음 |
| DT_WeaponData | 21530 | +8051 | +2898 | 양쪽 다 실질 변경 |
→ +5/+93B = 재직렬화 잡음(버려도 됨), +수KB = 실질 기능. 델타 크기가 판단 기준.
진단 3 — 출처 추적
git log --oneline <merge-base>..HEAD^2 -- <file>
# → 151파일짜리 단일 애니메이션 커밋이 참조 에셋을 부수적으로 재저장한 것 확인
복구 (커밋 아님, 워킹트리만)
git checkout 8c0defed7 -- "Content/.../BP_GA_Guard.uasset" # LFS 객체 로컬에 있으면 smudge로 실내용 복원
3. 머지 검증 — 양쪽 부모 diff + 균형/대칭 점검
머지커밋은 부모가 2개(HEAD^1=ours, HEAD^2=theirs). 두 방향 diff를 같이 보면 양쪽 의도가 다 보존됐는지 확인 가능.
git diff HEAD^1 HEAD -- <file> # ours → merged (= 그들이 가져온 변경)
git diff HEAD^2 HEAD -- <file> # theirs→ merged (= 우리가 가져온 변경)
함께 돌린 정적 점검:
- 잔여 충돌 마커:
grep -rE '^(<<<<<<<|=======|>>>>>>>)' Source/ - 파일별 여는/닫는 브레이스 개수 일치
- 네이티브 태그
.h의UE_DECLARE↔.cpp의UE_DEFINE1:1 대칭 (불일치 = 링크 에러). 빌드 링크 성공 = 대칭 보장됨.
비교 정리
| 항목 | 텍스트 코드 머지 | 바이너리(LFS) 머지 |
|---|---|---|
| 병합 방식 | 라인 단위 3-way | 한쪽 통째 선택 |
| 충돌 가시성 | <<<<<<< 마커로 드러남 |
조용히 한쪽 소실 |
| 진단 도구 | diff / 브레이스·마커 grep | oid 비교 + size 델타 + log 출처추적 |
| 흔한 사고 | 떨군 } → C2601 연쇄 |
기능 편집분이 재저장본에 덮임 |
| 복구 | 수동 재병합 | git checkout <commit> -- <file> |
'내일배움캠프_Unreal > TIL' 카테고리의 다른 글
| 내일배움캠프_Unreal/TIL - Day 143 (260625) (0) | 2026.06.25 |
|---|---|
| 내일배움캠프_Unreal/TIL - Day 141 (260623) (0) | 2026.06.23 |
| 내일배움캠프_Unreal/TIL - Day 137 (260617) (0) | 2026.06.17 |
| 내일배움캠프_Unreal/TIL - Day 135 (260615) (0) | 2026.06.15 |
| 내일배움캠프_Unreal/TIL - Day 133 (260611) (0) | 2026.06.11 |