기능가격문서블로그
mote 받기
← 블로그
개발·2026년 9월 7일·읽는 시간 5분

git checkout 뒤에도 문서가 비지 않도록, 시계 대신 바이트를 본다

브랜치를 바꿨더니 열어 둔 문서가 빈 화면이 된 적 있나요. 블로그에 실을 스크린샷을 찍다가 우리 앱에서 그 장면을 봤고, 고치는 김에 더 조용한 버그 하나를 같이 잡았어요.

m
mote
편집 중인 문서가 밖에서 바뀌었을 때 뜨는 배너. 다시 불러올지 계속 편집할지 고르게 하고, 상태 줄에는 아직 저장하지 않은 13 B가 남아 있어요.
편집 중인 문서가 밖에서 바뀌었을 때 뜨는 배너. 다시 불러올지 계속 편집할지 고르게 하고, 상태 줄에는 아직 저장하지 않은 13 B가 남아 있어요.

mote는 파일을 그대로 믿어요. 화면의 내용은 디스크의 바이트와 같고, 저장할 때도 그 바이트를 그대로 써요.

하지만 파일이 앱 밖에서 바뀌면 어떨까요? mote가 알아채지 못하면 다음 저장에서 다른 사람이 쓴 내용을 덮어쓸 수 있어요.

이 문제는 스크린샷을 찍다가 발견했어요. 브랜치를 오가며 ‘바뀌는 바이트’ 화면을 준비하던 중, 문서가 가끔 빈 화면으로 멈췄어요.

빈 화면 뒤에 숨은 두 가지 문제

git checkout은 파일을 한 번에 바꾸지 않아요. 기존 파일을 지우고, 새로 만든 뒤, 내용을 써요.

파일 감시자는 이 과정을 여러 이벤트로 알려 줘요. 그런데 mote는 첫 이벤트가 오자마자 파일을 읽고 있었어요. 아직 내용이 채워지기 전이라 빈 파일을 읽을 때가 있었죠.

파일을 다시 읽으면서 감시자도 새로 만들었어요. 그사이 이전 감시자에 남아 있던 이벤트는 사라졌고, 화면은 빈 채로 멈췄어요.

더 위험한 문제도 있었어요.

mote는 저장한 뒤 1.5초 동안 들어온 이벤트를 ‘내가 만든 변경’으로 보고 무시했어요. 하지만 그 안에 포매터나 저장 훅이 파일을 다시 바꿀 수도 있어요.

실제로 저장하고 0.3초 뒤 파일을 바꾸면, mote는 아무 변화도 보여 주지 않았어요. 사용자가 다시 저장하면 바깥에서 바뀐 내용은 조용히 사라졌고요.

하나는 눈에 보였고, 하나는 보이지 않았어요. 원인은 같았어요.

파일의 변화를 내용이 아니라 시간으로 판단하고 있었어요.

시간 대신 내용을 비교했어요

이제 파일 이벤트가 오면 바로 읽지 않아요. 200ms 동안 기다리고, 새 이벤트가 들어올 때마다 기다리는 시간을 다시 시작해요.

파일을 지우고 만들고 쓰는 과정이 끝난 뒤, 마지막 상태만 한 번 읽는 거예요. 오래된 타이머는 세대 번호로 무효화해요. 아무 일도 없을 때 계속 도는 타이머도 만들지 않았어요.

읽은 내용은 버퍼가 마지막으로 본 디스크 바이트와 비교해요.

같으면 앱이 저장했거나, 같은 내용이 다시 쓰인 거예요. 다르면 진짜 외부 변경이고요. 저장 후 0.1초가 지났는지, 1초가 지났는지는 중요하지 않아요.

같은 파일을 다시 읽을 때는 감시자도 유지해요. 감시자를 바꾸는 사이에 이벤트가 사라지지 않도록 했어요.

편집 중일 때만 물어요

외부 변경을 발견한 뒤에는 사용자의 상태를 살펴요.

저장하지 않은 편집이 있다면 배너를 보여 줘요. 바뀐 파일을 다시 불러올지, 지금 내용을 계속 편집할지 사용자가 고를 수 있어요. 어느 쪽을 선택해도 잃을 수 있는 내용이 있어서 앱이 대신 결정하지 않아요.

편집 중이 아니라면 바로 새 내용을 불러와요. 배너는 띄우지 않고, 캐럿과 스크롤 위치는 그대로 지켜요. 브랜치를 오가며 문서를 읽을 때는 알림보다 읽던 자리를 유지하는 편이 더 자연스러우니까요.

편집 중이 아닐 때 밖에서 바뀐 파일. 배너 없이 새 내용으로 바뀌었고, 제목의 편집 표시와 상태 줄의 대기 바이트가 사라졌어요.
편집 중이 아닐 때 밖에서 바뀐 파일. 배너 없이 새 내용으로 바뀌었고, 제목의 편집 표시와 상태 줄의 대기 바이트가 사라졌어요.

파일이 사라졌을 때도 바로 판단하지 않아요. 다른 편집기가 파일 이름을 바꾸는 중일 수 있어서 300ms 뒤에 다시 확인해요.

그때도 파일이 없으면 사용자에게 알려요. 작성하던 내용은 버퍼에 남아 있고, 다시 저장하면 파일을 만들어요.

실제 환경에서 여섯 가지를 확인해요

이 문제는 단위 테스트만으로 확인하기 어려워요. 파일 감시자와 실제 디스크, 창 관리자가 함께 움직일 때 생기기 때문이에요.

그래서 실제 환경에서 실행하는 검사를 만들었어요.

브랜치를 열 번 바꿔도 버퍼가 파일을 따라오는지, 저장 300ms 뒤에 파일을 바꿔도 반영되는지 확인해요. 앱이 직접 저장했을 때는 알림이 뜨지 않는지, 편집 중 외부 변경이 생기면 작성한 내용을 지킨 채 배너를 보여 주는지도 검사해요.

모두 여섯 가지예요. 릴리스할 때마다 실행해요.

tools/e2e/external.sh를 실기 디스플레이에서 돌린 출력. 여섯 줄이 모두 ok이고 마지막 줄이 PASS=6 FAIL=0이에요.
tools/e2e/external.sh를 실기 디스플레이에서 돌린 출력. 여섯 줄이 모두 ok이고 마지막 줄이 PASS=6 FAIL=0이에요.

파일을 진실로 다룬다는 건 저장한 내용을 그대로 쓰는 데서 끝나지 않아요.

파일이 우리 모르게 바뀌었을 때, 그 변화까지 놓치지 않아야 해요.

← 이전 글저장 중에 꺼져도 파일이 깨지지 않게 만든 방법
RSS로 새 글 받기
글을 위한 기본
한국어
© 2026 mote
멘토그래드 (MentorGrad) · 대표 윤상빈 · 사업자등록번호 475-15-02958 · 통신판매업신고 2026-서울도봉-0075 · 서울특별시 도봉구 마들로13길 61, 씨드큐브 창동, 4층 C동 411H호 · 010-2012-3741 · support@motemd.com