website: 서버 git 동기화를 pull에서 reset --hard로 전환
배포 서버의 dev 브랜치가 origin/dev보다 54커밋이나 앞서 있는 걸 발견하고, 원인을 추적해 cd.yml과 운영 문서의 git pull을 reset --hard로 바꾼 PR이다.
발단은 2026-07-26에 서버 dev와 origin/dev가 커밋 단위로 갈라져 있다는 걸 실측으로 확인한 일이었다. 그때는 로컬 전용 26개, origin 전용 16개 커밋으로 어긋나 있었고, 일단 git merge --no-commit --no-ff origin/dev 후 --abort로 미리 병합을 시험해봐서 충돌은 없다는 것까지만 확인하고 정리는 미뤄뒀다. RUNBOOK에도 "당장 급한 문제는 아니다"라고 남겨뒀던 항목이다.
그런데 7월 30일에 다시 확인해보니 이번엔 54커밋까지 벌어져 있었다. 26에서 54로 늘어난 걸 보고 이게 한 번 발생하고 끝나는 문제가 아니라 배포할 때마다 계속 쌓이는 구조적인 문제라는 게 명확해졌다. 원인을 다시 짚어보니, 서버 배포 키가 origin에 fetch만 되고 push는 안 되는 건(의도적 최소권한이라 이건 그대로 둬야 하는 설정) 문제가 아니었다. 진짜 원인은 cd.yml의 배포 스크립트와 RUNBOOK의 수동 배포 절차가 둘 다 git pull을 쓰고 있었다는 것이었다. pull은 내부적으로 fetch + merge인데, merge를 하면 로컬에만 있는 머지 커밋이 생긴다. 그 커밋을 서버는 다시 origin에 push할 권한이 없으니, 다음 배포에서 또 pull을 하면 또 새로운 로컬 전용 머지 커밋이 생기고, 이게 배포 횟수만큼 계속 누적되는 구조였다.
먼저 실측으로 안전한지부터 확인했다. 서버에 SSH로 접속해서 git fetch origin && git status -b로 ahead 54를 재확인하고, git diff origin/dev dev --stat로 실제 파일 내용 차이가 있는지 봤다. 결과는 파일 내용 차이는 전혀 없고 전부 빈 머지 커밋뿐이었다. 그래서 안전하게 git reset --hard origin/dev를 실행해서 ahead/behind를 0으로 맞추고, 이후 push-email-failure-metric.py 같은 배포 관련 스크립트들이 정상 동작하는지도 재확인했다.
정리만 하고 끝내면 다음 배포에서 다시 쌓이니까, 근본 원인인 cd.yml을 고쳐야 했다. 이미 git checkout -f TARGET_BRANCH만 git reset --hard origin/$TARGET_BRANCH로 바꾸면 됐다. 이 서버는 배포 대상일 뿐 로컬에서 직접 코드를 고치는 곳이 아니라서, 애초에 "지켜야 할 로컬 전용 커밋"이라는 게 존재할 이유가 없다는 게 reset --hard를 선택한 이유였다. pull이 필요한 merge 상황 자체가 이 서버에선 정상이 아니라 뭔가 잘못됐다는 신호라고 보는 게 맞다고 판단했다.
같은 패턴을 쓰던 문서들도 같이 고쳤다. RUNBOOK.md의 "infra/**만 바뀐 걸 배포할 때" 수동 절차, CI-CD.md의 배포 파이프라인 다이어그램도 pull을 reset --hard로 맞춰줬다. RUNBOOK에는 git checkout -f 없이 git reset --hard만 실행하면 브랜치 전환 없이 지금 체크아웃된 브랜치 자체를 덮어써버린다는 주의사항도 pull 때와 마찬가지로 남겼다 — 이건 2026-07-26 리뷰에서 발견했던 문제라 reset으로 바뀌어도 여전히 유효한 주의사항이었다.
observability.md도 손을 봤다. git 드리프트 감지 알람 문서에 "이 알람은 diverged 상태를 못 잡는 사각지대가 있다"는 서술이 있었는데, 이건 여전히 사실이지만(알람은 워킹트리 미커밋 변경만 보지 커밋된 채로 갈라진 상태는 못 본다) 그 원인이었던 pull의 병합 커밋 누적 자체가 이제 구조적으로 안 생기니까 "알려진 사각지대"에서 "알려진 사각지대였던 것 — 해소됨"으로 표현을 정정했다.
문서 쪽 정리는 첫 번째 커밋에서 infra/CLAUDE.md에 "서버 dev 동기화" 절을 새로 만들어 표준 절차를 남기고 해소된 미결 항목들을 지우는 것으로 시작했고, 두 번째 커밋에서 실제 CD 워크플로와 나머지 문서들을 고쳐서 재발을 막는 순서로 진행했다. 기록부터 남기고 코드를 고친 이유는, 왜 이렇게 바꾸는지 판단 근거를 먼저 정리해두면 이후에 cd.yml 같은 실제 배포 스크립트를 고칠 때 같은 논리를 그대로 재사용할 수 있어서였다.
이 PR은 인프라·문서만 건드려서 백엔드 코드 변경은 없었고, 생성부터 병합까지 30분 정도 걸려 바로 dev에 머지됐다. read-only 배포 키처럼 겉보기엔 문제없어 보이는 설정이라도, 그 위에서 쓰는 명령(pull vs reset)이 안 맞으면 조용히 누적되는 부작용이 생길 수 있다는 걸 실측 수치(26 → 54)로 확인한 경우였다. 다음엔 이런 종류의 drift는 발견 즉시 정리하기보다, 왜 계속 쌓이는지 근본 원인을 먼저 찾고 나서 정리하는 게 재작업을 줄이는 방법이라는 걸 다시 확인했다.