서울로 돌아와 노트북을 열었더니, 갈래가 두 개였습니다 🔀

부산 생활을 정리하고 서울로 다시 올라온 뒤 거의 3주 만에, 「여유」(관광 데이터로 만드는 여행 플래너, 지난 빌드로그에서 소개한 그 사이드 프로젝트입니다) 저장소를 열었습니다. 그동안 이 프로젝트는 사람 없이 주말마다 도는 자동화 에이전트가 돌보고 있었어요. 오랜만에 커밋 이력을 쭉 훑어봤더니, 낯선 그림이 나왔습니다. 한 줄로 이어져야 할 자리에서 브랜치가 둘로 갈라져 있었던 겁니다.
갈라진 자리를 그대로 따라가 봤다
git log --oneline --all --graph로 전체 이력을 펼쳐보니, main은 8월 26일 커밋에서 멈춰 있었습니다. 그 지점에서 두 개의 커밋이 각각 따로 뻗어 있었어요. 하나는 8월 29일 주말 세션이 만든 것으로 원격 저장소에만 올라가 있었고, 다른 하나는 8월 30일 주말 세션이 만든 것으로 제 로컬에만 남은 채 한 번도 올라간 적이 없었습니다. 두 커밋 다 같은 8월 26일 지점에서 갈라져 나온 형제였습니다.
문제는 배포였습니다. 이 프로젝트는 main에 커밋이 올라가면 자동으로 배포되는 구조인데, 두 주말의 작업이 서로 다른 갈래에 각각 갇혀 있었으니 실제 배포된 사이트에는 둘 다 반영되지 않은 상태였습니다. 2주 치 작업이 어딘가에는 있는데, 정작 눈에 보이는 화면에는 없는 상황이었던 거예요.
왜 똑같은 작업이 두 번 일어났나 🕳

두 커밋의 내용을 대조해보니 더 이상했습니다. 둘 다 정확히 같은 기능(명소 하나를 볼 때 연관 추천 후보들의 혼잡도를 조회하는 로직 축소)을 다루고 있었어요. 그런데 8월 29일 세션은 이 작업을 시작만 하고 멈춘 흔적이 있었고, 8월 30일 세션은 처음부터 다시 시작해서 끝까지 완성해놓은 상태였습니다.
8월 29일 세션이 왜 멈췄는지는 이 프로젝트에서 쓰는 보류 기록 파일(NEEDS-DECISION.md, 에이전트가 판단이 안 서면 여기에 적고 멈추는 규칙입니다)에 그대로 남아 있었습니다. 이유는 두 가지였어요. 하나는 외부 API가 이름을 완전히 일치시켜 걸러주는지 부분 일치까지 봐주는지 문서로 확인이 안 됐다는 것, 다른 하나는 방식을 바꾸면 기존 테스트 코드의 가짜 응답(목) 구조가 깨진다는 것이었습니다. 둘 다 무리해서 밀어붙이면 다른 요구사항(결과가 기존과 달라지면 안 된다는 조건)과 충돌할 위험이 있다고 판단해서, 에이전트는 코드를 건드리지 않고 이 파일에 판단거리만 남긴 채 멈췄습니다.
그런데 8월 30일 세션은 이 기록을 본 적이 없었습니다. 원인은 단순했습니다. 이 프로젝트의 주말 자동화는 매번 main의 최신 지점에서 새 브랜치를 팝니다. 8월 30일 세션이 브랜치를 새로 팠을 때 main은 여전히 8월 26일 지점이었고, 8월 29일 세션이 남긴 보류 기록은 8월 29일 브랜치 안에만 있었지 main에는 아직 올라가 있지 않았습니다. 그러니 8월 30일 세션이 연 NEEDS-DECISION.md는 8월 29일의 판단이 적히기 전 버전이었던 겁니다. 멈춰야 할 이유를 본 적이 없으니, 그냥 끝까지 구현해버린 거예요.
보류라고 적어둔 메모가, 다음 실행이 여는 화면에는 아예 없었던 겁니다.
정리는 어떻게 했나
다행히 8월 30일 세션의 결과물을 직접 뜯어보니, 8월 29일이 멈춘 이유 두 가지가 실제로는 해소돼 있었습니다. 이름 매칭 문제는 애초에 이름으로 거르는 서버 쪽 조건을 빼고 지역 단위로 한꺼번에 받아온 뒤 클라이언트에서 완전 일치로 다시 걸러내는 방식으로 피해 갔고, 테스트 목 구조는 이 새 방식에 맞춰 같이 다시 짜여 있었습니다. 단위 테스트 6개가 전부 통과했고, 실제 배포 환경에서 호출 수를 재보니 44번에서 34번으로 줄었는데 화면에 뜨는 결과는 이전과 바이트 단위까지 동일했습니다. 걱정했던 회귀가 없었다는 뜻이었죠.
그래서 8월 30일 결과물을 그대로 채택하기로 했습니다. 8월 29일 브랜치는 -s ours 옵션으로 병합해서, 코드는 다시 적용하지 않되 그 브랜치가 있었다는 역사와 그 안에 있던 문서 두 개(그날의 판단 기록)만 살려뒀습니다. 검증까지 마친 뒤 main에 올리고, 배포가 새 코드로 정상 반영된 걸 확인하고, 정리 끝난 낡은 브랜치들은 지웠습니다.
따라 하기
혼자 도는 자동화가 여러 세션에 걸쳐 돌아가고 있다면, 다음 세션이 이전 세션의 판단을 정말로 보고 시작하는지 한 번 확인해보시길 권합니다.
1. 브랜치 계보를 그래프로 펼쳐보기
git log --oneline --all --graph -20
- 여러 세션이 같은 지점에서 각자 브랜치를 판 적이 있는지, 그래프 모양만 봐도 드러납니다. 한 줄로 곧게 이어져야 할 자리에 갈림이 보이면 의심할 신호입니다.
2. 두 브랜치가 정말 같은 지점에서 갈라졌는지 확인하기
git merge-base <브랜치A> <브랜치B>
- 이 명령이 알려주는 공통 조상이 main의 최신 지점과 같다면, 두 브랜치는 “같은 출발선에서 각자 따로 진행된 결과물”이 맞습니다. 어느 한쪽이 다른 쪽을 이어받아 만든 게 아니라는 뜻이라, 둘 중 하나는 다른 하나의 판단을 아예 못 봤을 가능성이 큽니다.
3. 새 브랜치에 이전 세션의 보류 기록이 살아있는지 확인하기
git show <새-브랜치>:<보류-기록-파일-경로> | head -30
- 새 세션이 시작한 브랜치 안에서 그 파일을 열어, 직전 세션이 남긴 항목이 실제로 보이는지 확인합니다. 파일이 아예 없거나 옛날 버전이면, 이번 세션은 지난 판단을 모른 채로 시작하고 있는 겁니다.
✅ 이렇게 되면 성공 — 새 브랜치를 열자마자 직전 세션의 보류 기록이 그대로 보입니다.
⚠️ 막히면 — 러너 설정 자체가 매번 main에서 새로 브랜치를 파는 구조라면, 보류 기록을 남기는 커밋만큼은 그날 안에 main으로 병합하는 규칙을 별도로 넣으세요. 실제 작업은 브랜치에 남겨두더라도, “이건 지금 멈췄다”는 사실 하나는 다음 세션이 항상 볼 수 있는 곳에 있어야 합니다.
배운 것

8월 30일 세션이 잘못한 건 없었습니다. 오히려 8월 29일이 걱정했던 위험을 실제로 다 피해가면서 깔끔하게 완성했어요. 문제는 판단력이 아니라 구조에 있었습니다. 자동화가 매번 main에서 새로 시작하는 구조라면, 아직 main에 안 올라간 “이건 보류합니다”는 다음 세션에게는 아예 존재하지 않는 기록입니다.
이번에 정한 규칙은 하나입니다. 보류를 등록하는 커밋은 그날 안에 main으로 올려둘 것. 실제 작업은 여전히 며칠 걸릴 수 있지만, 적어도 “여기서 멈췄다”는 사실만은 다음에 이 저장소를 여는 게 사람이든 에이전트든 바로 볼 수 있게 해두는 게 이번 삽질에서 얻은 가장 실용적인 교훈이었습니다.
오늘도 한 걸음. 🐴
이 글은 산업 구조와 만드는 과정을 정리한 개인 기록입니다.
특정 종목의 매수·매도 추천이 아니며, 투자 판단과 그 결과는 독자 본인에게 있습니다.