내일배움캠프_Unreal/TIL

내일배움캠프_Unreal/TIL - Day 119 (260520)

하임 2026. 5. 20. 21:01

Git Master — sync-to-public 파이프라인 구축 완료

작업 목표

  • Public Repo 자동 동기화 워크플로(sync-to-public.yml) 안정화
  • GH008 LFS 에러 원인 파악 및 근본 해결
  • Git Lock 플러그인 운영 정책 확정

A. sync-to-public 워크플로 구조 설계

구현 내용

Private Repo의 develop에 PR이 머지될 때, Public Repo의 develop에 자동으로 동기화되는 워크플로 구축

핵심 설계 원칙:

  • PR 단위로 Public에 commit 1개 누적 (잔디 쌓임)
  • PR 제목 → Public commit 제목, PR 내 commit 목록 → body
  • rsync --delete로 삭제된 파일도 반영
  • LFS 객체 없이 포인터 텍스트만 push (lfs: false)
  • Squash 머지 환경에서 PR head SHA를 명시적으로 fetch해서 commit 목록 조회

새로 알게 된 것

  • git push public main --force로 history 통째 덮어쓰는 방식은 잔디를 매번 1개로 리셋시킴
    잔디 누적하려면 Public Repo를 git clone으로 받아 .git을 보존한 채로 rsync 후 일반 push해야 함
  • Squash 머지는 feature의 개별 commit을 develop history에서 끊어버리므로 git log base..head가 실패함
    git fetch origin <head_sha> --depth=100으로 orphan commit을 명시적으로 받아야 해결됨

B. GH008 LFS 에러 원인 분석과 해결

증상

remote: error: GH008: Your push referenced at least 137 unknown Git LFS objects
hint: Your push was rejected due to missing or corrupt local objects.


원인 추론 과정 (여러 AI 피드백 검증 포함)

주장  실제
"GitHub가 텍스트 내용을 스캔해서 LFS 시그니처 차단" ❌ GitHub가 blob 내용 직접 스캔하는 방식은 확인 안 됨
".gitattributes 없으면 포인터 push 완전 불가" ❌ .gitattributes 없으면 git은 LFS 검증 안 함
"Public Repo history에 과거 LFS 객체 참조 잔존" ✅ 실제 원인 — git lfs ls-files로 검증


진단 방법

git lfs ls-files
# 22개 파일이 LFS 추적 중
# .gitattributes는 없지만 과거 commit이 LFS 객체 참조 중

git log --all --oneline -- .gitattributes
# 7ea9a1c [프로젝트 초기 세팅] → 이때 LFS 추적이 걸림


해결 과정

  1. Orphan branch 초기화 시도 → develop, main 둘 다 처리. 그러나 새 push에서 또 GH008 발생
  2. 원인 재분석: Private에서 가져온 .uasset 파일이 LFS 포인터 텍스트를 내용으로 담고 있음. GitHub가 이 blob의 LFS 시그니처를 휴리스틱하게 감지해 LFS 객체 검증 발동
  3. 최종 해결: .uasset/.umap을 placeholder 일반 텍스트로 덮어씌워 LFS 시그니처 자체를 제거

Permission denied 발생 및 해결

.gitattributes의 lockable 속성으로 인해 .uasset이 read-only 상태. chmod +w로 쓰기 권한 부여 후 변환:

find . -type f \( -name "*.uasset" -o -name "*.umap" \) -exec chmod +w {} +
find . -type f \( -name "*.uasset" -o -name "*.umap" \) -print0 | \
while IFS= read -r -d '' file; do
  printf '%s\n' '[Portfolio Placeholder]' '' '...' > "$file"
done


새로 알게 된 것

  • git LFS의 lockable 속성은 lock하지 않은 파일을 read-only로 만들어 실수 수정을 방지함
    git lfs install --force + git checkout .으로 초기화 가능
  • Orphan branch는 과거 history를 새 commit으로 덮어쓰지만, 새 push에 LFS 포인터 텍스트가 담기면 또 걸림
    → history 문제가 아니라 blob 내용 문제였음
  • find -exec sh -c 'echo > "$1"' _ {} \; 방식은 공백 경로에 취약
    find -print0 | while IFS= read -r -d '' file 방식이 안전

C. Public Repo 운영 정책 확정

Placeholder 전략 채택

  • .uasset, .umap → 일반 텍스트 placeholder로 변환
  • 면접관이 GitHub Web에서 파일 클릭 시 "[Portfolio Placeholder] ..." 표시
  • 폴더 구조와 파일명으로 자체 제작 범위 파악 가능
  • LFS 대역폭 0 소모

워크플로 자동화 추가 단계

- name: Convert LFS Pointers to Placeholders
  run: |
    find . -type f \( -name "*.uasset" -o -name "*.umap" \) -exec chmod +w {} +
    find . -type f \( -name "*.uasset" -o -name "*.umap" \) -print0 | ...
    rm -f .gitattributes .lfsconfig

- name: Verify No LFS References
  run: |
    if grep -rln "version https://git-lfs.github.com" . 2>/dev/null; then
      exit 1
    fi

 

Public Repo 최종 상태

파일 유형 공개 방식

C++ 코드 (Source/) 그대로 공개
자체 제작 BP/Map (Content/Retrieve/) Placeholder 텍스트 (폴더 구조 보존)
유료 에셋 (Content/External/) 완전 제외 (rsync exclude)
Plugins GameplayMessageRouter만 공개, 나머지 exclude

주제 4: Git Lock 운영 정책 + 팀 전파

Status Branch 미사용 시 위험

LFS Lock은 동시 편집은 막지만, 오래된 버전 기반 작업은 막지 못함. develop이 앞서나간 상태에서 같은 파일을 lock하면 이전 팀원의 작업을 덮어쓸 수 있음

 

해결 방법: PR 전 develop 최신화 필수

[PR 직전 필수 로컬 최신화]

1. develop 브랜치 Fetch → Pull
2. 내 feature/* 브랜치로 이동
3. Merge:
   - Merge: develop
   - Into: feature/* (현재 작업 브랜치)
   - Merge Option: Default, Fast-forward if possible
4. PR 생성 후 "This branch is out-of-date" 경고 없는지 확인

 

타이밍: PR 제출 직전 1회 (작업 전에는 develop 최신화 후 Branch를 따올 예정)


회고

  • 목표 달성: sync-to-public 파이프라인 완전 안정화, 자동화 포함
  • 트러블슈팅 요약: GH008의 진짜 원인을 특정하는 데 시간이 가장 오래 걸림. "history 문제"와 "blob 내용 문제"를 구분하지 못해 orphan 리셋을 여러 번 시도함
  • 핵심 교훈: 에러 메시지에서 "어느 시점에" 발생하는지를 먼저 확인해야 함. LFS 에러가 push 시점에 발생하면 history 문제가 아니라 push 대상 blob의 내용 문제일 가능성이 높음