내일배움캠프_Unreal/TIL

내일배움캠프_Unreal/TIL - Day 140 (260622)

하임 2026. 6. 22. 21:02

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/
  • 파일별 여는/닫는 브레이스 개수 일치
  • 네이티브 태그 .hUE_DECLARE.cppUE_DEFINE 1:1 대칭 (불일치 = 링크 에러). 빌드 링크 성공 = 대칭 보장됨.

비교 정리

항목 텍스트 코드 머지 바이너리(LFS) 머지
병합 방식 라인 단위 3-way 한쪽 통째 선택
충돌 가시성 <<<<<<< 마커로 드러남 조용히 한쪽 소실
진단 도구 diff / 브레이스·마커 grep oid 비교 + size 델타 + log 출처추적
흔한 사고 떨군 } → C2601 연쇄 기능 편집분이 재저장본에 덮임
복구 수동 재병합 git checkout <commit> -- <file>