사용자가 정했다. 누가 언제 반영했는지는 소스에 남아야 하므로 머지 주석은 지금처럼 넣는다. 대신 비교하고 병합할 때는 그 줄을 무시한다. git 은 이 규칙을 모른다. 병합은 주석 줄도 글자로 보고 충돌을 낸다. 그래서 무시는 MergeHub 가 한다. - 2-Way, 3-Way, 폴더 비교에서 머지 주석을 차이로 세지 않는다 - 줄 끝에 붙은 주석은 조각만 떼고 견준다 - git 이 낸 충돌이 주석 차이뿐이면 묻지 않고 풀고, 두 주석을 다 남긴다 - 무시는 보는 방식일 뿐 파일에서 지우지 않는다. 설정에서 끌 수 있다 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
17 KiB
17 KiB
작업 지시 — MergeHub 6차 (병합을 끝까지 믿고 쓸 수 있게)
대상: D:\Sorce\MergeTool\MergeHub (플러그인) · D:\Sorce\MergeTool\UbisamPlatform (셸)
전제: 1~5차 지시서는 모두 끝났다(../진행상황.md).
이번 지시서가 나온 곳 — 5차 C-1 에서 만든 저장소(파일 303개 · 충돌 22개)로 병합을 MergeHub 만으로 커밋까지 해 봤다. 끝까지는 갔지만 걸린 것이 23가지였다. 그 목록이 이 지시서다. 근거와 수치는 ../history/2026-09-11-5차.md 의 C-1 에 있다.
| C-1 에서 잰 것 | 값 |
|---|---|
| 병합 결과 | git 과 똑같다 (UU 20 · AA 1 · UD 1 · M 7) |
| 3분할로 푼 파일의 줄끝 | 커밋에 CR 0개 (바탕은 줄마다 CRLF) — 105,025B → 101,810B |
| 파일 단위 Accept 결과 | 고른 쪽과 바이트까지 같다 (CRLF 그대로) |
| 충돌 탭 Accept 한 번 | 약 1.7초 (저장소 전체를 다시 읽는다) |
공통 규칙
- A → B → C → D 순서로 진행한다. A 는 파일이나 이력을 망가뜨리는 문제라 제일 먼저다.
- 항목 하나를 끝낼 때마다 빌드하고 실제로 실행해 화면을 확인한 뒤 보고한다.
- 항목 하나가 끝나면 기록을 세 군데에 남기고 로컬 커밋한다(4차 D-2 규칙).
- 상세는
doc/history/YYYY-MM-DD-주제.md— 원인 · 판단 · 확인한 결과 - ../진행상황.md 은 대기 → 완료로 상태만
- ../history/changelog.md 에 한 줄 — 날짜 · 무엇을 왜 · 커밋
- 상세는
- 푸쉬하지 않는다.
- 실제 소스를 열지 않는다(2026-09-11 결정). 시험 재료는 우리가 만들어 쓴다.
- 확인은 C-1 과 같은 저장소로 한다. 시험 저장소 생성기(
C1Repo)는 씨앗이 고정돼 있어 몇 번을 만들어도 같다. 고치기 전에 문제가 다시 나는 것부터 보이고, 고친 뒤 안 나는 것을 보인다. - 기존 검사 하네스 20벌(698건)은 계속 통과해야 한다. 로직을 건드리면 테스트를 먼저 늘린다.
- 빌드 경고 0 · 오류 0 을 유지한다. 앱이 실행 중이면
UbisamBase.Shell을 먼저 종료한다. - 플랫폼을 고치면 다른 소비 프로그램에 미치는 영향을 함께 적고
UbisamPlatform/doc/history/changelog.md에 남긴다.
A. 파일이나 이력을 망가뜨리는 것
C-1 에서 "심각" 으로 적은 다섯 가지다. A-1 · A-2 는 뿌리가 같다 — 병합 중에 "파일 하나를 풀어서 저장한다" 는 동작이 따로 없고 커밋까지 한 번에 묶여 있다. 둘을 같이 봐도 된다. 기록은 따로 남긴다.
A-1. 3분할로 푼 파일을 저장하면 CRLF 가 LF 로 바뀐다
- 충돌 파일을 3분할에서 풀고 저장하면 줄끝이 전부 LF 가 된다. CP949 파일도 같다. 실제로 고친 줄은 12줄인데 git 에는 파일 전체(3,367줄)가 바뀐 것으로 나온다. 현장 저장소에서 이러면 리뷰할 diff 가 사라지고, 다른 사람의 병합과 또 충돌한다.
- 상태바는
CRLF, 저장 형식은원본 유지였다. 화면이 말한 것과 다르게 썼다. - 짚이는 곳:
GitService.ResolveConflictWithContent가 저장 형식을 안 보고 글을 그대로 쓴다. 파일 단위 Accept 는 blob 을 바이트째 쓰므로 멀쩡하다 - 3분할 저장만의 문제다. - "원본" 이 무엇인지 정해야 한다. 충돌 중 워킹트리 파일에는 git 이 LF 로 충돌 표시를 넣어 두므로 그 파일을 보고 판단하면 틀린다. 내 쪽(ours) blob 의 줄끝을 기준으로 삼는 쪽이 맞아 보인다.
- 판정 기준: C-1 저장소에서
Motion/Unit0.cs를 3분할로 풀어 저장했을 때 줄 수와 CR 수가 같다.git diff --cached --stat이 고친 줄만 보여 준다. CP949 파일(Common/Util/한글설명.cs)도 같다.저장 형식에서 LF 를 고르면 그때는 LF 로 쓴다.
A-2. Save & Commit 이 "실패" 라는데 파일은 이미 써지고 스테이징됐다
- 충돌이 남아 있으면 커밋에서 막힌다. 그런데 그 앞의 "쓰고 스테이징" 은 이미 끝난 뒤라
충돌은 22 → 21 로 줄었는데 화면은
실패: 아직 해결되지 않은 충돌이 21건이라고 한다. - 그 뒤로 화면은 계속 저장 안 한 편집으로 여긴다. 다른 파일을 고르거나 Git 탭에서 Accept 를 누를 때마다 확인 창이 다시 뜬다. 여기서 "저장하고 계속" 을 누르면 한 번 더 쓴다.
- Git 모드에는 커밋 없이 저장하는 길이 없다. Ctrl+S 도 Save & Commit 이다. 병합 중에 파일 하나씩 풀어 둘 수가 없으니 22개를 한 번에 끝내야만 한다.
- 방향: 병합 중에는 "이 파일 해결로 저장" 이 따로 있어야 한다(쓰고 스테이징까지, 커밋은 안 함). Save & Commit 은 남은 충돌이 있으면 아무것도 하기 전에 막고 그 까닭을 말한다. 저장이 끝나면 편집 상태를 깨끗이 한다.
- 판정 기준: 충돌 22개 중 하나를 풀어 저장하면 충돌이 21개가 되고, 화면은 성공이라고 한다. 그 뒤 다른 파일을 골라도 확인 창이 안 뜬다. 남은 충돌이 있을 때 Save & Commit 을 누르면 파일도 스테이징도 안 바뀐다.
A-3. 충돌 파일을 고르면 상대(Theirs) 칸이 안 나온다
- 병합 중에 충돌 파일을 고르면 BASE 와 내 것 두 칸뿐이다. 3-Way 콤보는
(3-Way 안 씀). 상대가 무엇을 바꿨는지 안 보인 채 풀게 된다. 콤보에서 브랜치를 골라야 세 칸이 된다. - 짚이는 곳:
HomeViewModel.LoadFileAsync의 충돌 갈래가 지역 변수threeWay만 켜고 화면 틀을 정하는IsThreeWay는 안 켠다. - 병합 중의 상대 쪽은 브랜치가 아니라 인덱스(stage 3) 에서 온다. 콤보에 브랜치 이름을 고르게 하는 것도 뜻이 어긋난다.
- 판정 기준: 병합 중에 충돌 파일을 고르면 콤보를 건드리지 않아도 LOCAL · BASE · REMOTE · MERGED 네 칸이 뜬다. REMOTE 제목은 상대 브랜치 이름을 보여 준다. 충돌이 아닌 파일을 고르면 지금처럼 동작한다.
A-4. 상대가 지운 파일을 3분할이 다룰 줄 모른다
- 내가 고치고 상대가 지운 파일(UD)을 열면 REMOTE 칸이 비고, 범례는 "Theirs only 89" 라고 한다. 실은 내 쪽에만 있는 줄이다. 충돌은 10번 줄 하나로만 잡힌다.
- 진짜 물음은 "이 파일을 남길까 지울까" 인데, 3분할에는 지우는 길도 상대가 지웠다는 말도 없다.
(충돌 탭에만
상대쪽 삭제, 충돌 탭 Accept Theirs 를 누르면 제대로 지워진다.) - 반대 경우(내가 지우고 상대가 고침, DU)도 같이 본다. C-1 저장소에는 없으니 생성기에 하나 넣는다.
- 방향: 줄 단위로 끌고 가지 말고 파일 단위 선택(남긴다 / 지운다)으로 보여 준다.
- 판정 기준:
Recipe/ToBeDeleted.cs를 열면 "상대가 이 파일을 지웠습니다" 가 보이고, 남기기 · 지우기를 고를 수 있다. 범례가 줄의 주인을 바르게 말한다. DU 도 같은 식으로 풀린다.
A-5. 양쪽 새 파일에 Accept Both 를 누르면 빌드가 깨진다
- 양쪽이 같은 이름으로 새로 만든 파일(AA)에 Accept Both 를 누르면 두 파일을 바이트째 이어 붙인다. 결과 파일 한가운데에 BOM(EF BB BF)이 하나 더 들어가고, 같은 이름의 class 가 두 번 나온다.
- "둘 다" 는 줄 단위에서는 뜻이 있지만 파일 단위에서는 거의 늘 틀린 결과를 낸다.
- 방향: 이어 붙이더라도 뒤쪽 파일의 BOM 은 떼고, 줄끝을 앞쪽에 맞춘다. 그리고 파일 단위 Both 가 정말 필요한지 따진다 - 3분할에서 줄 단위로 둘 다 고르는 길이 이미 있다. 없애거나, 누르기 전에 "파일 두 개를 그대로 이어 붙입니다" 를 알린다.
- 판정 기준:
Ui/Views/NewPanel.cs에 Both 를 적용한 결과에 BOM 이 맨 앞 한 번만 있다. 줄끝이 한 가지로 맞다. Both 를 남긴다면 누르기 전에 무엇이 일어나는지 알 수 있다.
B. 헷갈리거나 막히는 것
B-1. 충돌 목록에서 3분할 화면까지 가는 길이 끊겨 있다
- 병합 뒤 파일 비교 탭의 파일 목록이 비어 있다(0개). 그 탭의 [새로고침] 을 눌러야 22개가 나온다. 앱을 새로 켜도 같다.
- 충돌 탭 목록을 두 번 눌러도 아무 일이 없다.
- 안내 글이 "홈 탭에서 해결하세요" · "홈 탭의 3분할 화면" 이라고 한다. 홈 탭은 없다(파일 비교 탭).
- 판정 기준: 병합이 끝나면 파일 비교 탭의 목록이 바로 채워진다. 충돌 탭에서 파일을 두 번 누르면 파일 비교 탭으로 넘어가 그 파일이 세 칸으로 열린다(A-3). 안내 글이 실제 탭 이름을 말한다.
B-2. 확인 창이 엉뚱한 파일 이름을 댄다
- 고친 것은
Motion/Unit0.cs인데 "ToBeDeleted.cs 에 저장하지 않은 편집이 있습니다" 라고 한다. 새로 고른 파일 이름을 가져다 쓴다(SelectedFile이 이미 바뀐 뒤에 묻는다). - 그 확인 창이 파일 콤보를 고르는 한가운데서 뜬다. 취소하면 콤보는 무엇을 가리키는지 불분명하다.
- 판정 기준: 확인 창이 편집한 파일의 이름을 댄다. 취소하면 콤보와 화면이 원래 파일 그대로다.
B-3. 커밋 메시지가 엉뚱하게 남는다
- 커밋 메시지가 처음 연 충돌 파일 것으로 굳는다. 다른 파일을 봐도, 앱을 껐다 켜도, 병합 커밋이 끝난 뒤에도 "Merge: Common/Util/Unit15.cs 충돌 해결" 이다.
- 충돌 탭의 [병합 커밋] 은 병합할 때 채워 둔 "Merge branch 'feature/theirs' into feature/mine" 을 안 쓰고 "Merge commit '1742d8f...'" 로 남긴다. git 이 주석으로 넣어 두는 "#Conflicts:" 와 파일 목록도 그대로 커밋된다.
- 판정 기준: 병합 커밋 메시지 첫 줄에 브랜치 이름이 들어가고
#로 시작하는 줄이 없다. 병합이 끝나면 파일 비교 탭의 커밋 메시지가 비워진다.
B-4. MERGED 칸 줄 번호가 네 자리에서 잘린다
- 3분할의 MERGED 칸에서 2949 → "294", 2950~2959 → 전부 "295". 1,000줄 넘는 파일은 줄 번호를 못 읽는다. 위의 세 칸은 멀쩡하다.
- 판정 기준:
Motion/Unit0.cs(3,367줄)를 열었을 때 네 칸 모두 끝 줄 번호까지 온전히 보인다. 7,479줄(실제 소스 최대 크기)짜리 만든 파일로도 확인한다.
B-5. 머지 주석은 소스에 넣고, 병합 뒤에는 그 줄을 무시한다
정한 것 (2026-09-14, 사용자) — 머지 주석은 지금처럼 소스에 넣는다. 누가 언제 반영했는지는 소스에 남아야 한다. 대신 비교하고 병합할 때는 그 줄을 무시한다.
- 지금의 문제: Take Theirs 한 자리마다 "// [김승준] 2026-09-14" 가 들어갔다. 다음 병합 때 양쪽이 서로 다른 주석을 같은 자리에 달고 있으면 그 주석 줄끼리 충돌하고, 비교 화면에는 주석 줄이 차이로 잡힌다.
- git 은 이 규칙을 모른다. 병합(libgit2)은 주석 줄도 글자로 보고 충돌을 낸다. 그러므로 무시는 MergeHub 가 한다.
- 비교 화면(2-Way · 3-Way · 폴더 비교) 에서 머지 주석을 차이로 세지 않는다.
알아보는 함수는 이미 있다(
MergeNote.LooksLikeNote). 지금은 2-Way 의 줄 필터만 규칙을 받고 3-Way 정렬(ThreeWayAligner)은 규칙을 안 받는다. - 줄 끝에 붙은 주석(
코드 // [이름] 날짜)도 있다(MergeNote.Append). 이 경우는 줄을 통째로 버리지 말고 주석 조각만 떼고 견준다. 코드가 같고 주석만 다르면 같은 줄이다. - git 이 낸 충돌이 머지 주석 차이뿐이면 사람에게 묻지 않고 MergeHub 가 푼다. 양쪽 주석을 모두 남기는 쪽으로 푼다 (이력은 지우지 않는다). 충돌 수에도 세지 않는다.
- 무시는 보는 방식이다. 파일에서 주석을 지우지 않는다. 설정에서 끌 수 있고, 끄면 지금처럼 차이로 보인다.
- 비교 화면(2-Way · 3-Way · 폴더 비교) 에서 머지 주석을 차이로 세지 않는다.
알아보는 함수는 이미 있다(
- 사람이 우연히 같은 모양(
// [글자] 0000-00-00)으로 쓴 주석도 무시된다. 이 한계는 설정 설명에 적는다. - 판정 기준
- 만든 저장소에서 양쪽 브랜치가 같은 코드 줄 위에 서로 다른 머지 주석만 달고 병합하면, git 은 충돌을 내지만 MergeHub 는 그 파일을 "충돌 0" 으로 보고 한 번에 풀린다. 두 주석이 다 남는다.
- 코드도 다르고 주석도 다르면 코드 충돌만 묻는다.
- 줄 끝 주석만 다른 줄은 비교 화면에서 같은 줄로 나온다.
- 설정을 끄면 지금처럼 차이·충돌로 보인다.
- 생성기(
C1Repo)에 이 경우들을 넣어 D-1 에서도 확인한다.
B-6. 충돌 탭에서 하나씩 누를 때마다 오래 기다린다
- Accept 한 번마다 저장소 전체를 다시 읽는다. 한 개 약 1.7초. 22개면 기다리는 것만 40초쯤이다.
- 여러 개를 골라 한 번에 Accept 하는 길이 없다.
- 판정 기준: 여러 개를 골라 한 번에 Mine/Theirs 를 적용할 수 있다. 다시 읽기는 끝에 한 번만 한다. C-1 저장소의 같은 줄 충돌 15개를 한 번에 풀었을 때 걸린 시간을 고치기 전과 견줘 보고한다.
B-7. 상태바가 병합 중에 믿을 수 없는 값을 보인다
- 인코딩·줄바꿈을 결과가 아니라 충돌 표시가 들어간 워킹트리 파일에서 읽는다. 양쪽이 다 CRLF 인 새 파일도 "UTF-8 · 혼합" 으로 나온다(A-1 과 같은 뿌리).
- "남은 차이 6줄" 은 충돌을 다 정해도 그대로다. "남은 충돌" 은 오른쪽 칸에만 나온다.
- 판정 기준: 병합 중 상태바의 인코딩·줄바꿈이 내 쪽(ours) 파일 기준이다. 상태바에 남은 충돌 수가 나오고 풀면 준다.
B-8. 병합 커밋 뒤 파일 비교 탭이 어정쩡하게 남는다
- 목록은 비고, 3분할 틀에 병합과 상관없는 파일(
Common/Util/Unit103.cs)이 BASE 칸에만 뜨고, 언어는 "평문" 이다. - 판정 기준: 병합 커밋이 끝나면 파일 비교 탭이 병합 전과 같은 보통 상태로 돌아간다(선택 커밋 = 방금 만든 병합 커밋).
C. 사소한 것
C-1. 로그와 목록 다듬기
- 병합 로그에 "충돌 22건 - 해결이 필요합니다." 가 두 번 찍힌다.
- 충돌 탭 목록의 종류 표시가 들쭉날쭉하다.
상대쪽 삭제만 있고 양쪽 새 파일(AA)은 표시가 없다. 몇 개 풀었는지(예: 3/22)도 없다. - 로그가 CP949 를 "ks_c_5601-1987" 로 적는다. 5차 A-1 에서 이름을 CP949 로 모았는데 이 자리가 빠졌다.
- 판정 기준: 로그가 한 번만 찍힌다. 목록에 충돌 종류(양쪽 수정 · 상대 삭제 · 내가 삭제 · 양쪽 새 파일)와 풀린 개수가 보인다. 로그의 인코딩 이름이 상태바와 같다.
D. 확인
D-1. 병합을 처음부터 다시 끝까지 해 본다
- A~C 를 다 고친 뒤 C-1 저장소를 새로 만들어 같은 병합을 처음부터 다시 한다. 이번에는 A-4 에 맞춰 생성기에 DU(내가 지우고 상대가 고침)를 하나 더 넣는다.
- 5차 C-1 과 같은 표로 결과를 적는다. 23가지 중 무엇이 사라졌고 무엇이 남았는지 한 줄씩.
- 새로 걸린 것이 있으면 C-1 때처럼 고치지 말고 적는다. 그 목록이 7차가 된다.
- 판정 기준: 충돌 22개(DU 포함 23개)를 MergeHub 만으로 풀어 병합 커밋까지 간다. 커밋된 파일 중 줄끝이 바탕과 달라진 파일이 0개다(파일 단위 · 3분할 둘 다). A 의 다섯 가지가 다시 나지 않는다.
이번 지시서에서 하지 않는 것
- 실제 소스로 병합해 보기 — 실제 소스는 열지 않는다(2026-09-11 결정). 만든 저장소로만 한다.
- rebase · cherry-pick 충돌 — 병합과 같은 3분할을 쓰지만 이번에는 병합만 끝까지 믿을 수 있게 만든다.
- 같은 줄 접기(4차 B-2) · 외부 편집기(4차 B-4) · 로그인·권한 — 미룬 그대로 둔다.
보고 형식
항목마다 이렇게 적는다.
- 고치기 전에 문제가 다시 나는 것을 어떻게 보였는지 (C-1 저장소의 어느 파일로)
- 무엇이 원인이었는지 한두 줄
- 어떤 파일을 어떻게 고쳤는지
- 실제로 실행해 확인한 결과 (바이트 · 줄끝 · 충돌 수처럼 눈이 아닌 값으로)
- 커밋 해시