Skip to content

fix(change): 신규 프로젝트의 첫 변경 내역이 diff 가 아니라 git 도움말이었다 - #317

Merged
dldnsgkr merged 1 commit into
developfrom
unhak/change-diff-without-repo
Sep 8, 2026
Merged

fix(change): 신규 프로젝트의 첫 변경 내역이 diff 가 아니라 git 도움말이었다#317
dldnsgkr merged 1 commit into
developfrom
unhak/change-diff-without-repo

Conversation

@dldnsgkr

@dldnsgkr dldnsgkr commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

"초기 프로젝트 생성 시에도 diff 를 볼 수 있나" 를 확인하다 발견.

증상

모든 신규 프로젝트의 첫 변경 내역이 diff 가 아니다. changes.diff_text 에 git 사용법 도움말이 통째로 들어가 있다.

원인 — 그 시점엔 .git 이 없다

순서
PreviewWorkspaceService#prepareProject 저장소 없는 신규 프로젝트는 조기 반환 — clone 도 init 도 안 함
ChangeService#record 여기서 diff 를 뜬다 (AgentPlanExecutor:112)
PreviewBranchPushService git init -b preview이제서야 저장소가 생김

.git 없이 git diff 를 돌리면:

$ (git add -N . || true) && git diff --no-ext-diff -- .
warning: Not a git repository. Use --no-index to compare two paths outside a working tree
usage: git diff --no-index [<options>] <path> <path>
... (도움말 100여 줄)
exit=129

그런데 exec 은 종료 코드를 보지 않는다(AGENTS.md 에 적힌 그 함정). 그래서 도움말 텍스트가 그대로 저장된다.

record 는 CODE 스텝당 한 번뿐이고 ResultApprovalService 도 diff 를 안 건드리므로 아무도 덮어쓰지 않는다 — 영구히 남는다.

수정

작업 트리 밖에 일회용 저장소를 만들어 거기서 뜬다:

git --git-dir=/tmp/qeploy-diff.git --work-tree=. init -q
git --git-dir=/tmp/qeploy-diff.git --work-tree=. add -N .
git --git-dir=/tmp/qeploy-diff.git --work-tree=. diff --no-ext-diff -- .

워크스페이스에 .git 을 만들지 않는 것이 핵심이다. 만들면 PreviewBranchPushService 가 "이미 저장소가 있다" 로 분기해, remote 도 없는 상태에서 git remote set-url 을 돌리다 push 가 통째로 실패한다.

로컬 검증: 정상 unified diff 출력, exit 0, 워크스페이스에 .git 안 생김, .gitignore 지켜짐(node_modules 미포함).

  • execexecWithExitCode. 이번 버그가 조용했던 진짜 원인이 종료 코드를 아무도 안 본 것이다. 실패하면 사유를 로그로 남기고 빈 값을 저장한다 — 도움말이 diff 인 척 남는 것보다 낫다. 변경 내역은 부가 정보라 CODE 스텝을 실패시키지는 않는다.
  • 100만 자 초과 시 절단(잘렸다는 것을 본문에 남김). 컬럼이 MEDIUMTEXT(16MB) 라 넘기면 저장이 통째로 실패해 작업을 다 해놓고 마지막에 죽는다.

이미 쌓인 행

되돌릴 수 없어 그대로 둔다 — 그 태스크의 컨테이너가 이미 없다.

검증

  • ChangeServiceTest 3개 신규 — 저장소 없을 때 작업 트리 밖에서 뜸 / 실패 시 빈 값 / 초과 시 절단
  • 기존 1개는 "저장소 있는 경로" 로 명시하도록 갱신
  • 전체 1333개 통과

🤖 Generated with Claude Code

https://claude.ai/code/session_013y8USoCXTsRTATAhy88M93

신규 프로젝트의 첫 CODE 스텝에는 컨테이너에 .git 이 없다. clone 은 저장소가 연결된
프로젝트에만 일어나고(PreviewWorkspaceService#prepareProject 가 조기 반환한다), git init 은
그보다 나중인 push 시점에 한 번 돈다(PreviewBranchPushService). 그런데 ChangeService#record
는 그 앞에서 불린다(AgentPlanExecutor:112 → 게이트/push 는 그 뒤).

그 상태로 git diff 를 돌리면 git 이 사용법 도움말을 뱉고 129 로 끝난다. 그런데 exec 은
종료 코드를 보지 않으므로(AGENTS.md 의 그 함정) 도움말 텍스트가 그대로 diff_text 에
저장됐다. record 는 CODE 스텝당 한 번뿐이고 ResultApprovalService 도 diff 를 안 건드리므로
아무도 덮어쓰지 않는다 — 즉 모든 신규 프로젝트의 첫 변경 내역이 영구히 쓰레기였다.

로컬 재현:
  $ (git add -N . || true) && git diff --no-ext-diff -- .
  warning: Not a git repository. Use --no-index to compare two paths outside a working tree
  usage: git diff --no-index [<options>] <path> <path>
  ... (도움말 100여 줄)   exit=129

- 저장소가 없으면 작업 트리 <b>밖</b>(/tmp/qeploy-diff.git)에 일회용 저장소를 만들어 거기서
  뜬다. 워크스페이스에 .git 을 만들지 않는 것이 핵심이다 — 만들면 PreviewBranchPushService 가
  "이미 저장소가 있다" 로 분기해 remote 도 없는 상태에서 git remote set-url 을 돌리다 push 가
  통째로 실패한다. .gitignore 는 그대로 지켜진다(node_modules 가 딸려오지 않는 것 확인).
- exec → execWithExitCode. 이번 버그가 조용했던 진짜 원인이 종료 코드를 아무도 안 본 것이다.
  실패하면 사유를 로그로 남기고 빈 값을 저장한다 — 도움말이 diff 인 척 남는 것보다 낫다.
  변경 내역은 부가 정보라 CODE 스텝을 실패시키지는 않는다.
- 100만 자를 넘으면 자르고 잘렸다는 것을 본문에 남긴다. 컬럼이 MEDIUMTEXT(16MB) 라 넘기면
  저장이 통째로 실패해, 작업을 다 해놓고 마지막에 죽는다.

이미 쌓인 잘못된 행은 되돌릴 수 없어 그대로 둔다(그 태스크의 컨테이너가 이미 없다).

검증: ChangeServiceTest 3개 신규(저장소 없을 때 작업 트리 밖에서 뜸 / 실패 시 빈 값 /
초과 시 절단), 기존 1개는 저장소 있는 경로로 명시, 전체 1333개 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013y8USoCXTsRTATAhy88M93
@dldnsgkr
dldnsgkr merged commit dd2fce1 into develop Sep 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant