SPACE LOGBOOK

OCEAN LOGBOOK

Git Commit의 정체..

2026.08.24

Git Commit의 정체..

2026.08.24

안다고 착각했던 깃 커밋의 정체

며칠 전, 운영 중인 회사 홈페이지 서버에서 이상한 일이 벌어졌다. 분명히 로컬 PC에서 작업하고, 서버에 배포하고, GitHub에 커밋·푸시까지 다 했는데 — 다음 날 확인해보니 서버의 git 기록이 완전히 어긋나 있었다. 파일은 멀쩡한데, 서버 git이 “너 커밋 안 한 변경사항 잔뜩 있는데?”라고 우기는 상황.

이 문제를 클로드 코드와 같이 파고들면서, 나는 1년 넘게 vibe coding을 해오면서도 정작 git commit이 뭘 하는 건지 절반만 이해하고 있었다는 걸 깨달았다. 부끄럽지만, 이 오해와 깨달음의 과정을 기록해둔다. 아마 나처럼 “커밋하고 푸시하면 끝”이라고 생각하는 사람이 또 있을 것 같아서.

사건의 발단 — 서버가 갑자기 헷갈려하다

상황은 이랬다. 며칠 전 집 PC에서 회사 홈페이지 테마 작업을 했다. 랜딩페이지 개편, 서비스 상세페이지 추가, 헤더·푸터 통일 작업까지 — 꽤 큰 작업이었다. 작업이 끝날 때마다 서버에 배포했고, 로컬에서는 GitHub로 커밋·푸시도 계속했다.

그런데 오늘 클로드 코드에게 “정리 좀 해줘”라고 요청했더니, 이런 보고가 돌아왔다.

로컬 ↔ GitHub: 완전 일치
서버: 완전히 다른 상황 — 서버 HEAD는 GitHub 최신 커밋을 전혀 받지 못한 상태

당황스러웠다. 분명 배포도 했고 커밋·푸시도 했는데 왜 서버만 뒤처져 있다는 거지? 심지어 “그대로 git pull 하면 충돌할 수도 있다”는 경고까지 붙어 있었다.

파일은 똑같은데, 왜 git은 다르다고 할까

클로드 코드가 로컬과 서버의 실제 파일을 md5 해시로 직접 비교해봤다. 결과는 완전히 동일. front-page.php, functions.php, header.php 등 핵심 파일 전부 한 글자도 다르지 않았다.

그럼 도대체 뭐가 “어긋나 있다”는 걸까? 여기서 나온 설명이 이번 사태의 핵심이었다.

서버에 배포된 실제 파일 내용은 GitHub 최신 버전과 100% 동일합니다. 문제는 서버의 git 커밋 기록이 이 배포를 반영하지 못한 것뿐이에요.

즉 “파일 내용”과 “git이 기록하는 정보”는 서로 다른 층위라는 거다. 나는 그동안 이 둘을 하나로 뭉뚱그려 생각하고 있었다.

내가 잘못 알고 있었던 것

나는 이렇게 이해하고 있었다.

로컬에서 작업 → 서버에 배포 → 로컬에서 GitHub에 커밋·푸시
= 로컬, 서버, GitHub 세 곳의 파일 내용이 같아졌으니 그걸로 끝이다.

파일 내용만 보면 이 생각은 틀리지 않았다. 하지만 여기엔 중요한 게 빠져 있었다. 배포(파일 복사)와 git 커밋은 완전히 별개의 통로라는 사실이다.

  • 로컬 → 서버: scp/ssh로 파일을 직접 복사하는 배포 (git과 무관)
  • 로컬 → GitHub: 정상적인 git commit → push

이 두 통로는 겉보기엔 같은 결과(파일이 최신화됨)를 만들지만, 서버의 git 저장소는 이 중 어느 쪽에도 연결되어 있지 않았다. 서버는 GitHub에서 pull을 받은 적도 없고, 로컬의 커밋 정보를 전달받은 적도 없다. 그저 파일만 누군가 조용히 바꿔치기해놓은 상태였을 뿐이다.

git 커밋이 진짜로 하는 일

이 사건을 통해 다시 이해하게 된 것은, git commit이 단순히 “이력을 남기는 기록 작업”이 아니라는 점이다.

git commit은 “이 파일들이 지금 어떤 스냅샷 상태인지”를 git 스스로가 판단하는 기준점을 만드는 작업이다.

서버에 파일만 새로 복사해 넣고 커밋을 하지 않으면, 그 파일 내용이 아무리 GitHub 최신본과 똑같아도 git 입장에서는 알 방법이 없다. git은 파일 내용을 실시간으로 GitHub와 비교하는 게 아니라, 오직 “마지막 커밋 이후 뭐가 바뀌었나”만 추적하기 때문이다. 그래서 서버 git은 최신 파일들을 전부 “정체불명의, 아직 확정되지 않은 변경사항 덩어리”로 인식하고 있었던 거다.

결론을 한 문장으로 정리하면

로컬에서 커밋·푸시를 했다면, 서버도 “나는 지금 그 커밋 시점까지 와 있다”는 걸 스스로 기록해줘야 한다. 서버가 로컬과 완전히 똑같은 커밋 히스토리를 가질 필요는 없다 — “지금 이 파일 상태 = 최신 반영됨”이라는 표식(커밋) 하나만 있으면 충분하다.

그림으로 정리하기 — 로컬과 서버, 각각 무슨 일이 있었나

말로만 풀면 헷갈리니, 로컬 PC와 서버 각각에서 실제로 무슨 일이 일어났는지 탭으로 나눠 그려봤다.

작업 파일
(코드 수정)
git add / commit →
로컬 git
커밋 스냅샷 생성됨
push →
GitHub
최신 커밋 반영
scp / ssh 로 파일 직접 복사
(git 시스템을 거치지 않음)
서버의 파일
내용은 최신으로 바뀜

로컬에서는 커밋(스냅샷 확정)과 배포(파일 복사)가 동시에 일어난 것처럼 느껴지지만, 실제로는 완전히 다른 두 개의 화살표다. 왼쪽 위 경로만 GitHub의 커밋 기록에 남고, 아래 경로(서버 배포)는 git과 무관하게 파일만 옮겨놓는다.

서버의 파일
내용: 최신 (GitHub와 동일)
git이 봤을 땐 ↴
서버 git
HEAD는 예전 커밋에 멈춰있음
✕ 최신 상태를 모름
↓ 여기서 서버가 직접 커밋해야 한다
서버 git
git add -A && commit 실행
✓ “지금 상태 = 최신”이라는 스냅샷 확보

서버는 파일 내용은 최신인데, git 기록만 예전 시점에 멈춰있는 상태였다. push는 필요 없다 — 서버가 GitHub에 다시 뭔가를 보낼 필요는 없으니까. 다만 서버 스스로 “나 지금 여기까지 왔어”라고 커밋 하나를 남겨야, 다음에 git이 헷갈리지 않는다.

그런데 왜 지금까지 몰랐을까 — 두 번째 발견

여기서 끝났으면 좋았을 텐데, 조사를 더 해보니 더 근본적인 문제가 하나 더 있었다. “배포”라는 게 애초에 고정된 스크립트로 이뤄진 게 아니라, 매번 클로드 코드가 그 자리에서 즉석으로 scp/ssh 명령을 만들어 실행해온 것이었다.

과거 세션 기록을 뒤져보니 이런 패턴이 나왔다.

scp -i server-key.pem single.php deploy-user@서버:/tmp/single.php.new
ssh -i server-key.pem deploy-user@서버 "sudo cp /tmp/single.php.new .../single.php"

이게 “배포 스크립트”처럼 보였던 deploy-backups/ 폴더의 날짜+기능명 백업 패턴조차, 사실 고정 로직이 아니라 그때그때 AI가 판단해서 만든 즉흥적 결과물이었다. 심지어 이 패턴이 집 PC 세션과 사무실 PC 세션에 나뉘어 남아있어서, 한쪽 PC에서는 다른 쪽에서 무슨 일이 있었는지조차 알 수 없었다.

scp 직접 실행 vs 배포 스크립트, 뭐가 다른가

결과적으로 서버에 파일이 올라간다는 점은 똑같다. 하지만 “무엇을, 어떻게, 얼마나 안정적으로” 하느냐에서 차이가 크다는 걸 이번에 제대로 체감했다.

구분scp 직접 실행 (즉흥적)배포 스크립트 (고정 절차)
대상 파일 선정그 순간의 기억/추론에 의존git diff 등으로 자동 산출
재현성매번 다를 수 있음항상 동일한 절차 보장
후속 작업 누락쉽게 빠뜨림 (이번 사태의 원인)스크립트에 고정하면 절대 안 빠짐
세션/PC가 바뀌어도맥락을 잃으면 재구성 어려움스크립트 파일 자체가 그대로 있어 동일 결과

비유하자면, scp 직접 실행은 매번 손으로 요리하면서 “이번엔 소금을 한 스푼 넣었나, 두 스푼이었나” 기억에 의존하는 것이고, 배포 스크립트는 레시피 카드를 만들어두고 매번 그대로 따라 하는 것이다. 레시피 카드가 없으니, 눈에 잘 안 띄는 단계(서버 커밋)가 슬쩍슬쩍 빠지기 시작한 거였다.

✦ ✦ ✦

정리하며

파일을 git 명령(pull / reset)으로 받으면 커밋 기록이 자동으로 따라오지만, 파일만 직접 복사(scp 등)로 받으면 커밋 기록은 따라오지 않는다.

그래서 서버가 커밋·푸시를 주도하고 로컬은 git reset --hard로 동기화만 하는 구조라면, 로컬이 별도로 커밋을 하지 않아도 애초에 문제가 생길 수 없다. 반대로 로컬이 커밋·푸시를 주도하고 서버는 파일만 배포로 받는 구조라면, 서버 배포 후 서버에서도 반드시 커밋을 남겨줘야 다음번에 git이 헷갈리지 않는다.

1년 넘게 vibe coding으로 시스템을 키워오면서도, git commit의 본질을 절반만 이해하고 있었다는 게 이번에 드러났다. “파일 내용이 같으면 다 된 거 아닌가?”라는 생각은 꽤 그럴듯해 보이지만, git은 파일 내용이 아니라 “내가 마지막으로 확인한 시점이 어디인지”를 기준으로 동작한다. 이 차이를 몰랐던 탓에, 서버는 계속 “지금이 어디쯤인지 모르는” 상태로 방치되고 있었다.

다행히 이번엔 실제 데이터 손실은 없었다. md5 해시로 확인해보니 서버 파일 내용이 GitHub 최신본과 완전히 동일했기 때문에, 설령 git reset --hard를 실행했어도 결과적으로 같은 내용을 같은 내용으로 덮어쓰는 셈이라 문제가 없었을 것이다.

다만 이건 “확인해봤더니 운 좋게 괜찮았다”였을 뿐, 확인하지 않은 상태에서 무작정 git pull이나 reset을 실행했다면 이야기가 달랐을 수 있다. 만약 서버에 GitHub에는 없는, 서버에서만 진행되다 만 미완성 작업이 남아있었다면, 그 변경사항은 확인 없이 통째로 날아갔을 것이다. 결과가 안전했던 건 사전 검증 덕분이지, 애초에 위험이 없었던 건 아니라는 뜻이다. 상태를 모르는 채로 되돌리기 명령을 실행하는 습관 자체가 위험 요소라는 걸 새삼 느꼈다.

비개발자로서 vibe coding을 하는 사람이라면 한 번쯤 겪을 법한 오해라, 기록으로 남겨둔다.

후기 — 결국 스크립트로 매듭짓다

글을 쓰다 말고, 이왕 원인을 알았으니 재발 방지까지 해두기로 했다. 클로드 코드와 함께 두 가지를 정리했다.

1. 서버 git 소유권 정리
그동안 일부 git 파일이 root 소유로 남아있어서, 서버에서 git 작업을 할 때마다 sudo가 필요했다. 이걸 배포 계정 소유로 통일해서, 이제 sudo 없이도 git add/commit이 가능해졌다.

2. 배포 스크립트 신설
그동안 “배포”라고 불러온 게 사실 고정 스크립트가 아니라 그때그때 즉석 명령이었다는 걸 이번에 알게 됐으니, 이참에 정식 스크립트를 하나 만들었다. 이 스크립트는:

  • git diff로 변경된 파일만 자동으로 찾아서 배포 대상으로 삼는다 (사람이 파일을 일일이 기억해서 지정할 필요 없음)
  • 서버로 옮기기 전, 기존 파일을 날짜+기능명 태그로 자동 백업한다
  • 배포가 끝나면 서버에서 직접 커밋까지 자동으로 실행한다 (push는 하지 않음 — 서버는 굳이 GitHub에 다시 보낼 필요가 없으니까)

즉 오늘 이 글에서 정리한 원칙 — “로컬이 커밋·푸시를 주도하는 구조라면, 서버 배포 후 서버에서도 반드시 커밋을 남겨줘야 한다” — 을 사람이 매번 기억해서 챙기는 대신, 스크립트가 배포할 때마다 자동으로 지켜주도록 만든 셈이다.

실제로 변경 파일이 있는 과거 시점을 기준으로 시험 실행(dry-run)을 해보니, 23개 파일의 변경 상태(수정/추가 등)까지 정확히 잡아냈고, 날짜+기능명 백업 태그도 예상대로 자동 생성됐다. 이제 다음에 진짜로 코드를 수정하고 이 스크립트로 배포하면, 서버 커밋 누락 같은 문제는 구조적으로 다시 일어날 수 없다.

개념을 안다고 착각했던 것에서 시작해, 그 개념이 왜 중요한지 몸으로 겪고, 마지막엔 다시는 안 잊어버리게 도구로 못박아둔 하루였다.

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 기록은 여기까지지만,
생각은 아직 이동 중이다