merge-safe
v1.0.0master 기준 기능 브랜치를 test 같은 통합 브랜치에 넣을 때 충돌을 별도 worktree 브랜치에서만 풀어 기능 브랜치를 오염시키지 않음
설치
호출 이름/merge-safe:merge-safe
merge-safe
master에서 딴 기능 브랜치를 test 같은 통합 브랜치에도 넣어야 하는데 충돌이 날 때, 기능 브랜치를 오염시키지 않고 충돌을 푸는 절차입니다.
뭘 하는지
master ──●── feature (그대로 유지) ───────────────→ master PR
\
origin/test ──●───────●── feature-to-test (충돌은 여기서만) → test PR
git merge-tree로 작업트리를 건드리지 않고 test·master 양쪽 충돌을 미리 봅니다origin/test에서--no-track브랜치를 별도 worktree로 땁니다- 거기서 기능 브랜치를 merge하고 충돌을 풉니다
- 합쳐진 상태로 타입 체크 후 push, test로 PR
- 기능 브랜치가 바뀌면 원본에 커밋 → to-test에 다시 merge
왜 이렇게 설계했나
흔한 해결법이 원본을 망가뜨린다
충돌이 나면 보통 기능 브랜치에서 git merge origin/test를 합니다. 그런데 test에는 운영에 안 나갈 다른 기능도 들어 있어서, 이 순간 그 코드가 전부 기능 브랜치로 들어오고 master PR에 같이 실립니다. 그래서 충돌 해결 장소를 통합 브랜치 쪽 복제 브랜치로 옮겼습니다.
worktree + --no-track
- worktree: 원본 작업트리에 커밋 안 된 변경이 있어도 stash·checkout 없이 그대로 둡니다.
--no-track:origin/test를 upstream으로 잡으면 무심코 친git push가 test에 바로 올라갈 수 있습니다.
방향은 한쪽으로만
수정은 항상 원본 기능 브랜치에서 하고, to-test는 받기만 합니다. 반대로 흐르면 master에 들어갈 브랜치에 test 코드가 섞입니다.
쓰는 법
test에 넣으려는데 충돌 나. 원본 브랜치는 건드리면 안 돼
기능 브랜치 고쳤으니 to-test에도 다시 반영해줘
안 쓰는 경우
- 통합 브랜치 없이 master로만 배포하는 흐름
- 충돌이 없어서 바로 PR하면 되는 경우
에이전트가 읽는 절차 — SKILL.md
설치하면 Claude가 실행 중에 참조하는 실제 문서다. 아래 내용이 그대로 동작을 결정한다.
merge-safe
Overview
test 같은 통합 브랜치에는 운영에 안 나갈 코드도 섞여 있다. 기능 브랜치에서 git merge origin/test로 충돌을 풀면 그 코드가 전부 기능 브랜치로 들어오고, 나중에 master PR에 같이 실려 나간다.
핵심 원칙: 충돌은 기능 브랜치가 아니라 통합 브랜치에서 딴 별도 브랜치에서 푼다. 기능 브랜치는 끝까지 master 기준 그대로 둔다.
master ──●── feature (그대로 유지) ───────────────→ master PR
\
origin/test ──●───────●── feature-to-test (충돌은 여기서만) → test PR
When to Use
- 기능 브랜치를 test/dev에 PR하려는데 충돌이 난다
- "원본 브랜치 손상되면 안 돼", "test엔 운영에 안 나갈 것도 있어"
Not for: 통합 브랜치 없이 master로만 가는 흐름, 충돌이 없는 경우(그냥 PR).
절차
1. 먼저 읽기 전용으로 충돌을 본다
git fetch origin
git merge-tree --write-tree origin/test <feature-branch> # exit 0 = 충돌 없음
git merge-tree --write-tree origin/master <feature-branch> # master 쪽도 같이 확인
작업트리를 전혀 건드리지 않는다. 충돌 파일 목록과 master 쪽이 깨끗한지를 먼저 사용자에게 보고한다.
2. 통합 브랜치에서 별도 브랜치를 worktree로 딴다
git worktree add --no-track -b <feature>-to-test ../<repo>-<feature>-to-test origin/test
--no-track:origin/test를 upstream으로 잡으면 실수로git push가 test에 직접 올라갈 수 있다.- worktree를 쓰면 원본 작업트리(미커밋 변경 포함)를 stash·checkout 없이 그대로 둔다.
- 앱이
.env를 읽으면 원본에서 복사한다(gitignore라 worktree엔 없다). 의존성은node_modules심볼릭 링크 등으로 연결.
3. 거기서 기능 브랜치를 merge하고 충돌을 푼다
git -C ../<repo>-<feature>-to-test merge --no-edit <feature-branch>
충돌 해결 원칙:
- 통합 브랜치에만 있는 블록 → 그대로 살린다 (남의 작업)
- 내 기능 블록 → 살린다
- 한쪽이 포매터 재정렬만 한 경우 → 로직이 있는 쪽을 살리고 포맷 차이는 버린다
- 양쪽이 같은 줄을 실제로 다르게 바꿨으면 멈추고 사용자에게 묻는다
git diff --check, 충돌 마커 grep으로 남은 마커가 없는지 확인한다.
4. 검증하고 push
- 그 worktree에서 타입 체크/빌드를 실제로 실행한다. 통합 브랜치의 다른 코드와 섞였을 때 깨지는 게 여기서 잡힌다.
git push -u origin <feature>-to-test→<feature>-to-test→test로 PR.- 기능 브랜치는
git log로 통합 브랜치 커밋이 안 섞였는지 확인한다.
5. 기능 브랜치가 또 바뀌면
원본 브랜치에 커밋·푸시 → to-test worktree에서 다시 merge → 양쪽 모두 타입 체크 → push. 반대 방향(to-test → feature)으로는 절대 merge하지 않는다.
- worktree에 커밋 안 된 변경(포매터 등)이 있으면 커밋에 섞지 말고 보고한다.
- 푸시 후 보안 리뷰 같은 자동 경고가 오면 내 변경인지 통합 브랜치에 원래 있던 코드인지 구분해 보고한다.
6. 끝나면
test PR이 머지되면 git worktree remove ../<repo>-<feature>-to-test. 브랜치 삭제는 사용자 승인 후.
Common Mistakes
| 실수 | 결과 |
|---|---|
기능 브랜치에서 git merge origin/test |
미출시 코드가 master PR에 같이 실림 |
| 기능 브랜치를 test 위로 rebase | 위와 같음 + 이미 push된 브랜치면 force push 필요 |
--no-track 없이 origin/test에서 브랜치 생성 |
git push가 test에 직접 올라갈 위험 |
| 원본 작업트리에서 checkout으로 전환 | 미커밋 변경 충돌·분실 |
| to-test 브랜치에서만 코드 수정 | 원본 브랜치와 갈라져 master엔 수정이 빠짐 — 수정은 항상 원본에서 |
| worktree에서 타입 체크 생략 | 합쳐진 상태에서만 나는 에러를 test 서버에서 발견 |