58 Commits

Author SHA1 Message Date
0485c60745 6차 A-2: 병합 중에는 [해결로 저장] 을 따로 둔다
Save & Commit 이 쓰기, 스테이징, 커밋을 한 덩어리로 돌려서 남은
충돌은 마지막 커밋 단계에서야 막혔다. 화면은 실패라는데 파일은
이미 써지고 스테이징됐고(충돌 22 -> 21), 편집 상태도 안 치워서
다른 파일을 고를 때마다 확인 창이 다시 떴다.

- MergeSavePlan: 지금 커밋해도 되는지 판단만 따로 뺐다
- Save & Commit: 병합 중 다른 충돌이 남으면 아무것도 쓰기 전에 멈춘다
- [해결로 저장]: 병합 중에만 보인다. 이 파일만 쓰고 스테이징한다
- Ctrl+S: 병합 중이면 해결로 저장
- 확인 창의 "저장하고 계속": 병합 중 충돌 파일이면 충돌까지 푼다

화면에서 해 보다 둘이 더 나왔다.
- 게이트에 막혀 건너뛴 목록 불러오기가 빈 결과로 목록을 비웠다.
  건너뛰면 그대로 두고, 해결로 저장 뒤에는 게이트가 풀릴 때까지
  기다렸다 다시 세운다(WhenIdleAsync). 남은 충돌 첫 파일이 열린다.
- 충돌을 전부 Take Mine 으로 정하면 글이 안 바뀌어 저장할 수 없었다.
  3분할에서 충돌을 다 정했으면 고친 글이 없어도 저장할 수 있다.

화면 확인 25건 통과. MergeSaveTest 18건 추가, 21벌 716건 통과.
경고 0, 오류 0. 줄끝(A-1)은 아직 그대로다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 10:22:48 +09:00
99a5d10775 지시서 6차 B-5: 머지 주석은 넣고 병합 뒤에는 무시한다
사용자가 정했다. 누가 언제 반영했는지는 소스에 남아야 하므로 머지
주석은 지금처럼 넣는다. 대신 비교하고 병합할 때는 그 줄을 무시한다.

git 은 이 규칙을 모른다. 병합은 주석 줄도 글자로 보고 충돌을 낸다.
그래서 무시는 MergeHub 가 한다.
- 2-Way, 3-Way, 폴더 비교에서 머지 주석을 차이로 세지 않는다
- 줄 끝에 붙은 주석은 조각만 떼고 견준다
- git 이 낸 충돌이 주석 차이뿐이면 묻지 않고 풀고, 두 주석을 다 남긴다
- 무시는 보는 방식일 뿐 파일에서 지우지 않는다. 설정에서 끌 수 있다

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 09:38:29 +09:00
ca634a9730 지시서 6차: 병합을 끝까지 믿고 쓸 수 있게
5차 C-1 에서 만든 저장소로 병합을 커밋까지 해 보고 걸린 23가지를
지시서로 묶었다.

A 파일이나 이력을 망가뜨리는 것 (C-1 에서 심각으로 적은 다섯)
  A-1 3분할 저장이 CRLF 를 LF 로 바꾼다
  A-2 Save & Commit 이 실패라는데 이미 써지고 스테이징됐다
  A-3 충돌 파일에 상대 칸이 안 나온다
  A-4 상대가 지운 파일을 3분할이 다룰 줄 모른다
  A-5 양쪽 새 파일에 Accept Both 가 빌드를 깬다
B 헷갈리거나 막히는 것 8 · C 사소한 것 1
D 고친 뒤 같은 저장소로 병합을 처음부터 다시 해 본다

확인은 C-1 과 같은 생성기로 한다. 고치기 전에 문제가 다시 나는
것부터 보인다. B-5(병합에 머지 주석을 넣을지)는 사용자가 정한다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 09:34:43 +09:00
015be282ac 5차 C-1: 병합을 끝까지 해 보고 걸린 것을 적는다
만든 저장소(파일 303개, 충돌 22개)로 MergeHub 만으로 병합해서
커밋까지 갔다. 지시서대로 고치지 않고 적기만 했다. 제품 코드는
바꾸지 않았다.

맞게 된 것: 병합 결과가 git 과 똑같다(UU 20 AA 1 UD 1 M 7).
3분할에서 충돌 6개를 6 -> 0 으로 줄였고, 파일 단위 Accept 는 고른
쪽과 바이트까지 같다. 부모 둘인 병합 커밋이 생겼다.

걸린 것 23가지. 심각한 다섯:
- 3분할로 푼 파일을 저장하면 CRLF 가 LF 로 바뀐다(커밋에 CR 0개)
- Save & Commit 이 실패라는데 파일은 이미 써지고 스테이징됐다
- 충돌 파일을 고르면 상대(Theirs) 칸이 안 나온다
- 상대가 지운 파일을 3분할이 다룰 줄 모른다
- 양쪽 새 파일에 Accept Both 를 누르면 BOM 이 가운데 하나 더 들어간다

기대값은 사본에서 git 으로 먼저 받아 대조했다. 실제 소스는
열지 않았다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 09:29:40 +09:00
c46abbd99a 5차 B-2: 폴더 비교를 세 걸음으로 나눠 3~5배 빠르게
훑기 - 가리기 - 세기로 나눴다. 훑으면서 그 자리에서 파일을 열어
견주던 것을, 트리를 먼저 세우고 가리는 일만 여러 갈래로 돌린다.
결과 차례는 트리가 정하므로 몇 갈래로 돌리든 같은 순서로 나온다.
세는 일만은 한 갈래로 한다. 파일이 64개 아래면 나누지 않는다 -
그 아래는 갈래를 세우는 값이 더 든다.

폴더를 훑는 방식도 바꿨다. Directory.GetFiles 는 이름만 주므로
파일마다 File.Exists 와 FileInfo 를 양쪽에 다시 물었다. 4,500개면
만 팔천 번이다. DirectoryInfo.GetFiles 는 크기와 수정 시각이
딸려 오므로 한 번으로 끝난다. 974ms 가 89ms 가 됐다.

재는 데 쓴 묶음은 우리가 만들었다(실제 소스를 열지 않는다).
2026-09-10 에 재 둔 모양을 흉내 냈고 씨앗을 고정해서 몇 번을
돌려도 똑같다.

  전체 비교  3,077ms -> 901ms (3.4배)
  빠른 비교  1,832ms -> 392ms (4.7배)
  앱에서 기다리는 시간 2,078ms -> 1,086ms (1.9배)

결과는 글자 하나까지 같다. 앱 쪽이 덜 줄어든 것은 비교가 끝난 뒤
화면 트리를 세우는 데 따로 드는 시간 때문이고, 거기는 손대지 않았다.
빠른 비교를 기본으로 켜지도 않았다 - 틀릴 수 있는 방법이다.

FolderTest 41 -> 51 (갈래 나누는 길, 열 번 돌려 같은 결과, 취소).
전체 698건 통과(하네스 20벌). 경고 0 · 오류 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:35:16 +09:00
9c0106be57 지시서 5차: 실제 소스를 더 읽지 않는다
여기는 머지툴을 만드는 자리다. 남의 저장소를 읽을 까닭이 더 남아
있지 않고, 읽는 동안 사고가 날 여지만 있다. 이미 받아 둔 숫자
(XAML 400개, CP949 67개, 4,503개에 12.2초)는 그대로 쓴다.

B-2 와 C-1 을 그에 맞게 다시 썼다. 둘 다 큰 재료가 필요한데,
이제 우리가 만들어 쓴다. 만든 묶음은 몇 번을 돌려도 같은 값이
나와서 재기에는 오히려 낫다. C-1 에는 그 한계도 같이 적었다 -
만든 소스에는 진짜 코드의 지저분함이 없다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:06:07 +09:00
26446d5e6b 5차 B-1: XAML 태그·속성·값을 갈라 칠한다
실제 소스에 XAML 이 400개 42,477줄인데 여태 주석과 따옴표만 알아봐서
사실상 평문이었다. 마크업 전용 토크나이저를 따로 뒀다.

기존 토크나이저에 못 얹은 까닭은 규칙이 다르기 때문이다. 그쪽은 낱말을
읽어 예약어 표와 맞춰 보는데, 마크업은 같은 Content 가 꺾쇠 안에서는
속성 이름이고 밖에서는 그냥 글자다. 낱말이 무엇이냐가 아니라 어디에
있느냐로 갈린다.

줄 넘김 상태를 bool 하나에서 깃발 묶음(CarryOver)으로 넓혔다. XAML 은
여는 태그가 여러 줄에 걸치는 것이 보통이라 - 시험에 쓴 실제 파일은 첫
태그 하나가 14줄이다 - "지금 꺾쇠 안이다"를 안 넘기면 이어지는 줄의
속성이 그냥 글자로 보인다. 부르는 자리 다섯을 모두 바꿨다.

색은 새로 만들지 않고 이미 있는 갈래에 얹었다. 태그는 예약어 색,
속성 이름은 메서드 색, 값은 문자열 색, 앞가지는 타입 색이다. 태그
밖의 본문은 일부러 안 칠한다.

붙이는 중에 파일 비교 화면이 통째로 비어서 뜨는 일이 있었다. 의존
속성 타입을 bool 에서 CarryOver 로 바꾸면서 기본값 false 를 같이 안
고쳤다. 빌드도 통과하고 로그에도 안 남는다. 같은 주의를 코드 옆에
적어 뒀다.

실제 저장소 XAML 사본(638줄)으로 화면 확인. C# 색칠은 그대로.
MarkupTest 65건. 전체 688건 통과(하네스 20벌). 경고 0 · 오류 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:01:58 +09:00
238910634c 5차 A-2: Git 작업을 시작하는 자리에서 묻는다
커밋·체크아웃 뒤에 저장 안 한 편집이 말없이 사라지던 것을 막았다.

막는 자리를 옮겼다. 목록을 다시 세우는 자리(RefreshCommits →
LoadCommitAsync)가 아니라 Git 작업이 시작되는 문(GitWorkspace.
RunAndRefreshAsync)에서 묻는다. 그 순간에는 아직 아무것도 바뀌지
않았으므로 취소가 뜻을 가진다.

작업을 가려서 묻는 쪽은 접었다. fetch·태그·스테이징처럼 파일을 안
건드리는 열두 가지는 안 물으려 했는데, 해 보니 그런 작업 뒤에도
편집이 사라졌다. 파일이 그대로여도 저장소를 다시 읽으면서 본문을
새로 그리기 때문이다. 다시 그리지 않게 막는 쪽도 해 봤지만 고른
파일까지 바뀌는 경우가 있어 조건을 세울 수 없었다. 잃지 않는 쪽으로
갔다 - 확인 창은 고치던 것이 있을 때만 뜨고, 틀려도 한 번 더 묻는
것으로 끝난다. 알아낸 열두 이름은 KnownSafeCandidates 에 남겼다.

덤으로 4차 A-1 이 새던 자리 셋을 막았다. 목록을 다시 세우면 화면이
값을 되밀어 넣는데, 그것을 사람이 고른 것으로 보고 확인 창을 띄우고
있었다. OnSelectedNodeChanged(null·같은 커밋), OnRemoteBranchChanged
(_syncingBranches), Files.Clear()(_suspendGuard 안으로).

화면 시험 10건 통과(데모 저장소). GitOpTest 36건. 전체 623건 통과
(하네스 19벌). 빌드 경고 0 · 오류 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 13:21:33 +09:00
8e28a16fc2 5차 A-1: 실제 소스 인코딩 확인 - 깨지는 파일 0개
실제 저장소 2091개를 MergeHub 로 읽어 봤다. CP949 67개 포함해 깨짐 0, 저장 왕복 어긋남 0.
판별 코드가 TextFile 과 GitService 두 군데에 복사돼 있던 것을 한 곳으로 모았다.
상태바가 KS_C_5601-1987, 목록이 CP949 로 같은 것을 다르게 부르던 것도 맞췄다.
2026-09-11 08:44:16 +09:00
dafb606f8f 작업지시-5차: 실제 소스에 맞추기 다섯 항목
지금까지 시험용 파일로만 확인했다. 실제 저장소를 재 보고 나온 것들로 채웠다.
CP949 67개 · XAML 400개 · 폴더 비교 12초 · 실전 병합.
대용량 성능은 답이 나와 미룬 것에서 뺐다 - 가장 큰 파일이 7479줄이고 다 빠르다.
2026-09-10 22:52:44 +09:00
9aa69f2c57 진행 상황: 4차 지시서 마무리 기록
D → A → B → C 를 하루에 다 걸었다. 남은 항목 없음(B-2 · B-4 는 사용자 판단으로 취소).
취소한 둘은 미룬 것 목록으로 옮기고 다시 꺼낼 조건을 적었다.
2026-09-10 22:45:37 +09:00
bad30f50e4 4차 C-5: ACTIONS 칸을 자주 쓰는 것과 한 번 정하는 것으로 나눔
저장 형식·비교 규칙·편집 잠금을 한자리에 모아 접었다. 차이 이동을 개수 옆으로 옮겼다.
지시서의 "폭이 넓어진다"는 틀렸다. 폭을 정하는 단추들이 접어도 남는 쪽이다.
2026-09-10 22:39:26 +09:00
27a8bfb275 C-4 다시: 범례가 눌러진다는 사실이 안 보였다
새 단추가 아니라 원래 항목이 눌러지는 것이라 찾을 수가 없었다.
항목마다 테두리를 주면 시끄러우므로 줄 머리에서 한 번만 말한다 - 색 구분 (눌러서 이동).
2026-09-10 22:29:57 +09:00
bc92676a49 4차 C-4: 색 구분 범례를 이동 도구로
개수를 누르면 그 갈래 줄로 가고 다시 누르면 다음 줄로 간다. 차이 이동과 같은 방식이다.
0건은 흐리게만 하고 숨기지 않는다. 자리가 움직이면 다시 찾아야 한다.
2026-09-10 22:18:06 +09:00
06d018742a C-3 다시: 접힌 것이 있다는 사실이 안 보였다
11px 회색에 화살표 하나로는 여기 접힌 것이 있다는 게 전해지지 않았다.
글자에 펴기/접기를 넣고 굵은 강조색으로 키웠다.
2026-09-10 22:10:11 +09:00
d8c8d6c6f7 4차 C-3: Git 탭의 원격 칸을 접는다
원격 저장소가 없어 전부 비활성인 세 줄이 위쪽 4분의 1을 차지했다. 지우지 않고 접었다.
새로고침은 로컬 작업이라 로컬 경로 줄로 옮겼다.
펼침 상태는 설정에 남기되 Browsable(false) 로 설정 화면에는 안 내놓는다.
2026-09-10 22:06:44 +09:00
aa30988a35 엔터 고침이 만든 되돌이 문제를 고침
TextChanged 안에서 재정렬을 부르니 편집기 글을 자기 이벤트 안에서 갈아 끼우게 됐다.
캐럿이 엉키고 글자가 엉뚱한 자리에 찍혔다.
타이머 간격을 1ms 로 두어 이 입력이 끝난 다음 차례에 돌게 했다. 속도는 그대로다.
2026-09-10 21:59:16 +09:00
06de091735 엔터를 누르면 한참 뒤에 반응하던 것
줄 수가 바뀌면 한 줄만 고치는 빠른 길이 손을 떼고 0.6초 타이머만 남았다.
편집기 글자는 투명이라 그동안 화면에 아무것도 안 나왔다.
못 맞춘 경우 그 자리에서 재정렬하게 했다. 엔터가 글자 한 자와 같은 값이 됐다.
2026-09-10 21:48:14 +09:00
cbf9e64539 4차 C-2: 아래쪽 정보를 창 아래 한 줄로
같은 뜻의 숫자가 세 군데에 있었다. 왼쪽은 어디, 가운데는 얼마나 남았나, 오른쪽은 무슨 파일인가.
패널 밖으로 나오면서 두 패널 코드 영역 높이가 저절로 같아진다.
2026-09-10 21:40:28 +09:00
9f0802e58f C-1: 경로를 읽으라고 적는다
늘 똑같은 BASE/LOCAL 이 크고 정작 경로가 회색 작은 글씨였다. 뒤집었다.
접두사를 빼고 본문 색 고정폭 12px 로, 갈리는 첫 칸만 굵은 강조색.
2026-09-10 21:30:29 +09:00
a6877d7b13 C-1 다시: 머리글에 두 경로의 다른 부분을 남긴다
파일 이름만 남기니 양쪽이 똑같이 보였다. 파일 비교는 이름이 같은 경우가 오히려 흔하다.
PathUtil.DistinctTail 로 같은 앞부분만 떼고 나머지를 적는다. 검사 11건 추가.
2026-09-10 21:21:14 +09:00
9d9fa40ddf 4차 C-1: 같은 경로가 세 군데 나오던 것
패널의 경로 줄과 위 툴바의 잘린 경로를 없애고 머리글 툴팁으로 모았다.
복사는 우클릭 메뉴로, 끌어다 놓는 자리는 단추로 옮겨 둘 다 지켰다.
2026-09-10 21:15:40 +09:00
2ac4a5a987 4차 B-2 같은 줄 접기 - 취소
접기가 풀려는 문제를 차이 이동·미니맵·다음 파일이 이미 대부분 풀고 있다.
반면 목록을 둘로 나누는 일은 122군데를 건드리고 틀리면 저장이 깨진다.
WinMerge 확인 결과와 다시 꺼낼 조건을 지시서에 적었다.
2026-09-10 21:10:20 +09:00
278b471480 4차 B-4 외부 편집기로 열기 - 취소
사용자 판단으로 뺀다. 채워 넣을 설정 값이 둘인데 얻는 것보다 수고가 크다.
번호는 3차 D-4 와 같이 그대로 둔다.
2026-09-10 21:02:28 +09:00
8083075ece 4차 B-3: 폴더 비교에서 다음 다른 파일로
훑는 중인 목록을 GitWorkspace 에 두고 파일 비교 화면에서 이전/다음으로 딛는다.
화면에 보이는 순서를 따르고, 찾은 줄 목록도 같은 방식으로 훑는다.
먼저 묻고 자리를 옮긴다. Ctrl+PageUp/PageDown.
2026-09-10 20:49:46 +09:00
b9456b7f14 4차 B-1: 최근 비교 목록
파일 짝과 폴더 짝을 따로 15개까지 기억한다. 탭으로 나눈 글로 설정 폴더에 둔다.
없는 경로는 흐리게 보여 주고 지우지 않는다. 검사 33건 추가.
2026-09-10 20:43:14 +09:00
0625236fc3 4차 A-2: 내보낸 보고서에 만든 사람을 넣음
이름 판단을 MergeNote.AuthorOf 로 모아 머지 주석과 보고서가 같은 이름을 쓴다.
이름이 비면 줄 자체를 넣지 않는다. 검사 8건 추가.
2026-09-10 20:34:28 +09:00
7278829d1e 4차 A-1: 저장하지 않은 편집이 말없이 사라지던 것
본문을 다시 읽는 열한 군데를 조사해 여덟 군데를 막았다.
비교 규칙 변경은 편집을 지키므로 손대지 않았고, 커밋 새로고침은 일부러 두었다.
파일을 새로 열어도 HasChanges 가 안 꺼지던 것을 함께 고쳤다.
2026-09-10 20:29:52 +09:00
0994d514fb 4차 D-2: 앞으로의 기록 규칙을 공통 규칙에 못박음
항목을 끝내면 상세는 history 날짜 파일, 진행상황은 상태만, changelog 는 한 줄.
진행 순서를 D → A → B → C 로 고쳤다. D 를 먼저 하라는 말이 D 묶음 안에만 있었다.
플랫폼 changelog 경로를 풀어 적었다. 같은 이름 파일이 둘이 되어 헷갈린다.
2026-09-10 20:17:17 +09:00
b82e40a17c 4차 D-1: 변경 이력을 doc/history/ 로 나눔
721줄짜리 진행상황.md 를 날짜별 파일과 changelog 로 나누고 73줄로 줄였다.
지시서 네 개는 git mv 로 doc/작업지시/ 에 모았다. 링크 15개 전부 살아 있다.
옮기기만 하고 내용은 고치지 않았다.
2026-09-10 20:15:57 +09:00
d82db6572b 작업지시-4차에 D 묶음(변경 이력 전용 폴더) 추가
690줄짜리 진행상황.md 를 doc/history/ 의 날짜별 파일과 changelog 로 나눈다.
기록하는 자리를 바꾸는 일이라 A~C 보다 먼저 하는 편이 낫다고 적었다.
2026-09-09 16:45:14 +09:00
c870eacfe8 작업지시-4차에 C 묶음(화면 구성 정리) 추가
경로 중복 · 하단 정보 흩어짐 · Git 원격 블록 접기 · 색 구분 범례 · ACTIONS 칸 나누기 다섯 가지.
3-Way 원본 칸 접기는 행 잠금을 건드리는 같은 성격이라 B-2 에 묶었다.
2026-09-09 16:01:41 +09:00
c846474e4b 작업지시-4차: 로컬 머지툴 사용성 6항목
A 작업한 것이 사라지는 문제 2건, B 매일 쓰는 마찰 4건.
진행상황에 대기 표를 함께 넣었다.
2026-09-09 15:55:16 +09:00
13314641d7 진행 상황: 3차 지시서 마무리 기록
A~E 를 하루에 다 걷었다. 남은 항목 없음(D-4 만 사용자 판단으로 취소).
미룬 것 목록에서 끝난 두 가지(끌어다 놓기 · 결과 내보내기)를 뺐다.
완료 기록에 2026-09-09 네 줄을 넣었다.
2026-09-09 15:37:30 +09:00
196af0a913 D-7 끌어다 놓기를 화면에서 확인하고 세 군데를 고쳤다
경로 칸(TextBox)이 Drop 을 먼저 먹어 놓아도 아무 일이 없었다 - Preview 로 옮겼다.
파일 비교의 경로 글자는 Background 가 없어 놓을 자리 자체가 없었다.
칸에 놓아도 다시 견주지 않던 것을 DropFile / DropFolder 로 고쳤다.
파일을 하나씩 놓아 짝을 만들 수 있게 했다.
검색 결과 칸에 머리글을 넣고 줄 간격을 목록과 맞췄다.
2026-09-09 15:32:52 +09:00
373990b3b6 D-7, D-3: 끌어다 놓기 · 폴더 안 전체 검색
D-7 은 코드만 끝났다. 화면이 잠겨 탐색기에서 끄는 확인을 못 했다.
D-3 은 UI 자동화로 검색·결과 열기·취소까지 확인했다.
2026-09-09 15:16:19 +09:00
ee5d34c2a6 D-6: 비교 결과 텍스트 내보내기
결과를 남에게 보내거나 결재에 붙일 때 화면을 캡처하는 것 말고는 방법이 없었다.
캡처는 검색도 안 되고 줄 번호를 짚어 말하기도 어렵다.

Services/CompareReport.cs 신설. 파일 비교와 폴더 비교 양쪽에서 쓴다. 글을
만드는 일만 여기서 하고, 어디에 저장할지 묻는 것은 화면 쪽 일이다. 그래야
화면 없이 검사한다.

파일 쪽은 요약과 다른 줄 목록을 적는다. 줄 번호는 양쪽을 다 적는다. 한쪽에만
있는 줄이 있어 번호가 어긋나므로 하나만 적으면 파일에서 그 줄을 찾을 수 없다.
폴더 쪽은 상태와 상대 경로를 줄마다 적는다. 폴더 자체는 적지 않는다. 그 안의
파일이 이미 다 적혀 있다.

곁들여 요약에 주석만 다른 수를 덧붙였다. "다름 3(주석만 1)". D-1 로 새로 생긴
갈래가 요약에는 안 보였다.

확인: 두 화면에서 각각 뽑아 메모장으로 열었다. ReportTest 23건 신설.
전체 451건 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 14:49:02 +09:00
32c0146b48 3-Way 에서 BASE 가 비어 있으면 그 까닭을 머리글에 적는다
WeldController.cpp 를 3-Way 로 열면 BASE 칸이 통째로 비어 보였다. 고장이
아니다. 두 브랜치의 공통 조상(9b48b82)에는 그 파일이 아예 없다. master 와
feature/cpp-tuning 이 각자 새로 만든 파일이라 견줄 조상이 없다. 그래서 모든
줄이 "양쪽에서 새로 넣은 줄"이 되고 충돌 6개가 나온다.

다만 화면이 그 사실을 말해 주지 않았다. 빈 칸은 누가 봐도 고장으로 읽힌다.
BASE 머리글에 "이 파일 없음 - 양쪽에서 새로 만든 파일입니다" 라고 적는다.
조상에 파일이 있으면 지금까지처럼 파일 이름이 나온다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 14:39:09 +09:00
451b6245cb D-1: 주석만 다른 파일을 다른 색으로
폴더 비교에 "주석만 다름" 상태를 새로 두었다. 코드는 같고 주석/공백만 다른
파일이다. 봐야 할 성격이 다르다. 주석만 손댄 파일은 눈으로 훑고 넘길 수
있는데 다른 것과 같은 색으로 섞여 있으면 전부 열어 봐야 한다.

판단은 주석 토큰을 걷어내고 공백을 지운 뒤 견주는 것이다. 주석 기호는 언어마다
다르므로 확장자로 고른 언어표를 따르고, 언어를 모르는 파일은 하지 않는다.
양쪽 확장자가 다르면 같은 언어로 볼 근거가 없으니 역시 하지 않는다.
줄 구분은 코드가 있는 줄에만 남긴다. 큰 파일은 건너뛴다.

곁들여 색 뜻풀이 줄을 목록 위에 붙이고, 보기 필터에 "코드가 다른 것만"을
더했다. 주석만 다른 것을 빼고 보는 쪽이 실제로 필요한 동작이다.

확인: 주석만 고친 .cs 는 회색 "주석만 다름", 값이 바뀐 .cs 와 평문 .txt 는
노란 "다름". "코드가 다른 것만"을 고르면 앞의 것이 빠진다.
FolderTest 4건 추가. 전체 428건 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 14:33:25 +09:00
5c8c942ba5 D-2, D-5: C++ 전처리 지시문 · 3-Way 덩어리 반영
D-2. C++ 문법 강조는 이미 되고 있었다. LanguageProfile.CFamily 가 확장자
아홉 가지를 맡고 예약어/주석/문자열도 들어 있다. 빠진 것은 전처리 지시문
하나였다. #include 가 # 과 include 로 쪼개져 보통 낱말처럼 칠해졌다. 줄
첫머리가 # 이면 그 줄 전체를 지시문 색으로 칠한다. C# 쪽과 같은 규칙이다.
언어표에 hasPreprocessor 를 두어 C 계열에서만 켠다.

D-5. 2-Way 는 이미 됐다. 3-Way 가 잘못 동작하고 있었다. 덩어리를 BASE 에서
가져오고 있었는데 3-Way 에서 BASE 는 공통 조상이다. 저쪽(REMOTE)을 가져오는
것이 Take Theirs 이고 덩어리 반영은 그것을 줄 묶음으로 하는 것인데, BASE 를
가져오면 조상으로 되돌리는 셈이라 뜻이 전혀 달라진다. 덩어리를 묶는 기준도
모드에 맞췄다.

확인: 충돌 6개짜리 C++ 파일에서 다음 충돌 -> 이 덩어리 반영 한 번에 네 줄이
REMOTE 값으로 바뀌고 Conflict 6 -> 2. LangTest 12건 추가. 전체 424건 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 14:22:55 +09:00
4f33cacd4f E-5, E-6: 반영 색 유지 · 차이 이동 시 코드 겹침
E-5. 줄을 반영한 뒤 비교 규칙을 하나 건드리면 초록(머지 반영함)이던 줄이
보라(직접 수정)로 바뀌었다.

반영 표시가 되돌리기 스택에만 있었다. 규칙을 바꾸면 화면을 통째로 다시
만들면서 그 스택을 비운다. 그러면 표시가 사라지고 남는 단서는 "글이 원본과
다르다"뿐이라 직접 수정으로 칠해진다. B-3 에서 Take Mine 이 충돌을 못 지우던
것과 같은 뿌리다.

- 반영할 때 줄 번호로도 남긴다. BASE 줄 번호, 없으면 MINE 줄 번호.
- 다시 만들 때 반영 여부를 먼저 본다. 반영한 줄은 직접 수정 조건에도 걸린다.
- 되돌리면 그 기록도 함께 지운다.

곁들여 머지 주석 줄도 같은 이유로 보라색이 됐다. 주석 줄이라는 표시 역시 줄
객체에만 있어서 다시 만들면 사라진다. 글을 보고 알아보게 했다
(MergeNote.LooksLikeNote).

E-6. Alt+위/아래로 차이를 옮겨 다니면 칸 아래 상태바 위에 코드가 겹쳐
그려졌다. 표시층은 편집기 글자와 눈높이를 맞추려고 RenderTransform 으로 살짝
밀어 두는데, 그건 배치가 아니라 그리기라 칸 밖으로 나가도 막는 것이 없다.
격자의 행도 자기 칸 밖으로 나가는 자식을 자르지 않는다. 코드가 놓이는 자리를
자르는 상자로 감쌌다. 네 칸 모두.

확인: 반영 후 공백/Aa 규칙을 눌러도 머지 반영함 2 · 직접 수정 0 그대로.
Alt+아래 8회, Alt+위 6회 눌러도 마지막 줄이 경계에서 깨끗이 잘린다.
NoteTest 13건 추가. 전체 399 -> 412건 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 13:50:13 +09:00
05c74fcb0e C 묶음: 코드 툴팁 · 글자 잘림 · 폴더 복사 확인 창
C-1. 코드 위에 마우스를 올리면 그 줄 내용이 그대로 툴팁으로 다시 떴다. 글이
이미 보이는데 같은 글이 상자로 겹쳐 뜨니 가리기만 한다. 원본 세 칸에서 뺐다.
버튼과 상태 아이콘 툴팁은 그대로 둔다. 그쪽은 화면에 없는 정보를 알려 준다.

C-2. Git 탭 목록의 글자가 ... 없이 중간에서 뚝 끊겼다. 줄임표 설정은 이미
있었는데 듣지 않았다. 목록의 가로 스크롤이 켜져 있으면 항목이 제 글 길이만큼
넓게 잡히고, 그러면 잘릴 일이 없으니 줄임표도 나오지 않는다. 가로 스크롤을
끄면 항목이 칸 너비에 갇히고 그때 비로소 줄임표가 나온다. 커밋/변경 파일/
브랜치/충돌/태그/서브모듈 여섯 목록에 같이 걸었다.

"작업 취소" 버튼과 Git 탭 입력 칸이 잘리는 것은 재현하지 못했다. 2560x1600 과
1920x1080 에서 배율 100%/120% 로 여섯 하위 탭을 모두 봤지만 멀쩡했다.

C-3. 폴더 복사 확인 창을 윈도우 기본 대화상자에서 플랫폼 것으로 바꿨다.
글꼴도 색도 배치도 혼자 달라 "이 프로그램이 묻는 것"으로 읽히지 않았다.
묻는 것 자체는 없애지 않았다. 복사/삭제는 되돌릴 수 없다.

확인: 코드 위 3초 머물러도 툴팁 없음. 이력 목록이 ... 로 줄어듦. 폴더 복사
확인 창과 완료 토스트가 프로그램의 다른 알림과 같은 모양.
테스트 399건 그대로 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 13:24:03 +09:00
8def1add2a E-4: 2-Way 로 돌아오면 LOCAL 옆에 빈 칸이 남던 문제
3-Way 에서 구분선을 끌어 칸 폭을 바꾼 뒤 2-Way 로 돌아오면 LOCAL 오른쪽에 칸
하나만 한 빈 자리가 남았다. 구분선을 건드리지 않으면 멀쩡했다.

GridSplitter 는 끌고 나면 양옆 칸을 비율(star)이 아니라 고정 픽셀로 바꿔 놓는다.
그러면 창 크기가 바뀌어도 칸이 따라 늘지 않고, 2-Way 로 돌아와 REMOTE 칸이
접히면서 생긴 자리를 아무도 채우지 않는다. 늘어날 star 칸이 없기 때문이다.

- 구분선을 놓는 순간 고정 픽셀을 같은 비율의 star 로 되돌린다. 잡아 놓은 폭은
  유지되면서 창 크기를 따라간다.
- 2-Way <-> 3-Way 를 오갈 때는 세 칸의 폭 지정을 놓아준다. 배치가 통째로 다르고,
  REMOTE 칸은 폭을 Style 이 정하는데 끌어서 생긴 값이 남으면 2-Way 에서 접히지
  않는다.

확인: 3-Way 에서 구분선을 끌고 2-Way 로 돌아와도 두 칸이 폭을 꽉 채운다.
테스트 399건 그대로 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 11:40:07 +09:00
9a9c431b43 E 묶음: 세로 막대 · 폭 되돌림 · 머리 빈 공간
E-1. 원본 세 칸에 세로 스크롤 막대를 켰다.
가로와 달리 세로는 이 칸들이 실제로 굴러가므로 ScrollViewer 가 주는 막대를
그대로 쓴다. 대신 막대가 자리를 차지하는 만큼 여백 보정을 걷어냈다. 전에는
편집기 막대 폭만큼 오른쪽 여백을 줘서 글자 폭을 맞췄는데, 이제 진짜 막대가 그
자리를 차지하므로 여백까지 주면 글자 폭이 좁아져 접히는 자리가 어긋난다.

E-2. 칸 폭을 줄였다 늘리면 행 높이가 돌아오지 않던 문제.
행 높이는 각 칸이 알려 온 글 높이 중 가장 큰 것을 쓴다. 그런데 글자를 그리는
칸이 세로로 늘어나 있어서(WPF 기본값 Stretch) 행이 한 번 커지면 그 다음부터는
"행 높이만큼 높다"고 되돌려 보냈다. 자기가 만든 값을 자기가 다시 읽는 셈이라
높이가 올라가기만 하고 내려오지 않았다. 글자 칸을 위로 붙여 자기 글 높이만
알리도록 고쳤다.

E-3. 경로 줄과 코드 사이의 빈 공간.
패널 머리 높이를 상수로 못 박아 두어(124 / 74) 실제 내용보다 훨씬 컸다.
상수를 없애고 내용에 맞춰 줄어들게 한 뒤, 나란히 놓인 칸끼리는 SharedSizeGroup
으로 가장 큰 것에 맞춘다(REMOTE 만 Conflict 줄이 하나 더 있다). 2-Way 에서는
MERGED 머리도 같은 무리에 넣고 3-Way 에서는 뺀다.
2-Way 에서 한 화면에 보이는 코드가 29줄에서 34줄로 늘었다.

확인: 세로 막대를 끌면 세 칸이 함께 움직인다. 2560x1600 <-> 1920x1080 을
오가도, 가운데 구분선을 끌었다 되돌려도 처음과 같은 화면이 된다.
테스트 399건 그대로 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 11:29:56 +09:00
179dffb1ad B 묶음: 3-Way 화면 세 가지
B-1. 원본 세 칸에 가로 스크롤 막대 신설.
이 칸들은 ScrollViewer 를 가로로 굴리지 않고(줄 번호까지 밀려 나간다) 글자만
SourceShiftX 로 민다. 그래서 ScrollViewer 가 만드는 막대는 움직이지 않는
막대가 되어 감춰 두고 있었고, 긴 줄이 있다는 사실 자체를 알 수 없었다.
막대를 따로 놓고 SourceShiftX 와 값을 서로 맞춘다.

B-2. 워드랩을 켠 3-Way 에서 세로 스크롤이 아예 안 되던 문제.
원인이 둘이었다.
- 메아리를 막는 자물쇠를 try/finally 로 그 자리에서 풀고 있었다. 목록의 스크롤
  알림은 배치가 끝난 다음에 오므로 그때는 이미 열려 있었고, 그 메아리가 다시
  편집기를 굴렸다. 이제 그 일로 밀려서 오는 알림이 다 지나간 뒤에 푼다.
- 두 좌표계를 픽셀로 환산하고 있었는데, 목록이 가상화라 안 그려진 행의 높이를
  알 수 없어 환산이 어긋났다. 워드랩일 때는 행 단위로 굴려 "몇 번째 행이 맨
  위인가"만 주고받는다.
곁들여, 편집기 맨 위 행을 스크롤 값 나눗셈이 아니라 좌표로 물어본다.

B-3. Take Mine 을 눌러도 남은 충돌이 줄지 않던 문제.
"내 것으로 간다"는 결정은 글을 바꾸지 않아 되돌리기 스택에 남지 않는데,
RefreshAppliedFlags 가 스택만 보고 반영 표시를 다시 칠하면서 그 표시를 지웠다.
줄 번호로 기억해 둔 결정을 같이 보도록 고치고, 같은 판단을 IsDecidedAsMine
하나로 합쳤다.

확인: 막대 끌기/가로 휠/워드랩 토글, 워드랩 켠 채 네 칸이 같은 행을 맨 위에
놓는 것, 충돌 6개를 Take Mine/Theirs 번갈아 눌러 "충돌 정리 끝"까지.
테스트 399건 그대로 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 11:10:40 +09:00
b5bd06cb49 A-5 다시: 폴더 고르는 창을 윈도우 폴더 선택 창으로 바꿈
요구를 잘못 읽었었다. Git 저장소 이야기로 보고 .git 찾아 올라가기를 만들었는데,
실제로는 폴더 비교 탭의 폴더 고르는 창 이야기였다. 상위 폴더를 골라 놓고
하위까지 한꺼번에 비교하고 싶은데 그 상위 폴더를 고를 방법이 없었다.

원인은 폴더 고르기를 파일 열기 창으로 돌려쓰고 있던 것이다. 이 방식은 지금 서
있는 폴더를 돌려주기 때문에, 목록에 보이는 폴더를 고르려면 반드시 그 안으로
들어가야 한다. 그래서 늘 가장 깊은 폴더만 골라졌다.

- 윈도우 폴더 선택 창을 셸 COM(IFileDialog + FOS_PICKFOLDERS)으로 직접 부른다.
  목록에서 폴더를 한 번 눌러 고를 수 있다. COM 이 안 되면 전에 쓰던 방식으로
  물러선다.
- SetDefaultFolder 가 아니라 SetFolder 를 쓴다. 전자는 윈도우가 기억한 폴더를
  우선해서 지금 경로 칸에 적힌 폴더에서 열리지 않는다.
- D-4(비교 창 여러 개)는 사용자 판단으로 취소. 번호는 그대로 둔다.

확인: 위로 한 번 올라가 목록의 right 폴더를 한 번 눌러 골랐고 경로 칸에 그대로
들어왔다. 그 상태로 비교하니 doc / src / src·core / src·ui 트리가 나오고
src·core·weld.cs 까지 펼쳐진다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 10:00:38 +09:00
93a507e3e8 A-5: Git 저장소 최상위를 고를 수 없던 문제
두 가지가 겹쳐 있었다.

하나. Git 탭의 폴더 고르기가 WinForms FolderBrowserDialog 였다. net48 에서는
주소 칸이 없는 옛날 트리 창이라 경로를 붙여넣을 수 없고, 지난번에 골랐던 깊은
폴더에서 최상위까지 손으로 거슬러 올라가야 했다.

둘. .git 은 최상위에만 있는데 LooksLikeRepository 가 고른 폴더 바로 밑만 봤다.
사람은 지금 보고 있던 깊은 폴더를 고르기 마련이라 멀쩡한 저장소를 두고
"저장소가 아니다"가 됐다.

- Services/FolderPicker.cs 신설. 폴더 고르기를 한 군데로 모았다(폴더 비교
  왼쪽/오른쪽, Git 저장소 경로, 변경분 추출 대상 폴더).
- PathUtil.FindRepositoryRoot 신설. 고른 자리에서 위로 올라가며 .git 을 찾는다.
  워크트리/서브모듈은 .git 이 파일이라 둘 다 본다. 안쪽에 저장소가 또 있으면
  가장 가까운 것을 잡는다.
- Git 탭과 시작 시 자동 열기가 같은 규칙을 쓴다.

확인: src\MergeHub\Views\GitView.xaml (네 단계 아래)을 골랐더니 경로가
D:\Sorce\MergeTool\MergeHub 로 바로잡히고 저장소가 열렸다.
PathTest 12건 추가(31 -> 43건). 전체 399건.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 09:52:17 +09:00
af27800978 진행 상황: A-2~A-4 화면 이동 결함 기록
고친 곳은 플랫폼(UbisamPlatform 저장소)이고, 여기에는 무엇이 원인이었고
어떻게 확인했는지를 남긴다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 09:45:10 +09:00
5e667af35a A-1: 폴더·파일 고르기에서 프로그램이 죽던 문제
원인은 경로에 섞인 슬래시였다. 폴더 칸에 C:/Users/... 처럼 슬래시가 섞인
값이 들어 있으면 Directory.Exists 는 통과시키지만, 대화상자의
InitialDirectory 는 윈도우 셸(COM)이 그대로 해석하다 ArgumentException 을
던진다. 그 예외는 대입할 때가 아니라 ShowDialog() 안쪽에서 올라오기 때문에
대입 줄만 try 로 감싸 둔 파일 비교 쪽도 똑같이 죽게 돼 있었다.

- Services/PathUtil.cs 신설. 셸에 넘길 경로는 전부 여기를 거친다.
- 폴더·파일 고르기 둘 다 ShowDialog() 를 감쌌다. 끊긴 네트워크 드라이브처럼
  정규화로 걸러지지 않는 경우에는 시작 폴더 없이 한 번 더 연다.
- 3차 작업 지시서와 진행 상황 문서 신설·갱신.

검사: PathTest 31건 신설(356 -> 387건). 실제 실행으로 왼쪽·오른쪽 폴더 10회
연속, 파일 비교의 기준·내 파일 각 1회 확인.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 09:28:13 +09:00
4029336b88 밖에서 부르기: 명령줄 인자 수신 · 탐색기 보내기 등록
git config 에 mergetool/difftool 로 등록하는 쪽은 전부터 있었는데 정작 그 인자를
받는 쪽이 없어 다리가 반만 놓여 있었다. 나머지 반쪽을 놓고, 탐색기에서도 부를 수 있게 했다.

- Services/StartupArgs: 켤 때 넘어온 인자를 읽는다.
  이름표 붙은 것(--merge --base B --local L --remote R --merged M)과 그냥 넘어온 경로
  둘 다 받는다. 경로가 폴더면 폴더 비교로, 파일이면 파일 비교로 보낸다.
  difftool 의 LOCAL/REMOTE 와 셸이 주는 "먼저 고른 것/나중 것" 은 뜻이 달라 따로 담는다 -
  이 도구의 왼쪽은 늘 "기준"이라 difftool 에서는 REMOTE 가 왼쪽이 된다.

- Services/ShellIntegration: 탐색기 "보내기" 메뉴에 바로가기를 둔다.
  처음에는 우클릭 메뉴에 바로 넣으려고 레지스트리에 정적 verb 를 등록했다
  (HKCU\Software\Classes\AllFilesystemObjects\shell\...). 키는 제대로 들어갔고
  HKEY_CLASSES_ROOT 에도 병합돼 보였는데 탐색기 메뉴에는 뜨지 않았다.
  확인해 보니 이 PC 에서 우클릭 메뉴에 나오는 다른 프로그램(Notepad++ · Git Bash ·
  WinMerge)은 전부 HKLM 에 등록돼 있었고, HKCU 에 넣은 것은 - 우리 것이든 확인용으로
  넣어 본 메모장 항목이든 - 하나도 그려지지 않았다. HKLM 은 관리자 권한이 필요해 쓸 수 없다.

  그래서 보내기(SendTo)로 갔다. %APPDATA%\Microsoft\Windows\SendTo 에 바로가기 파일
  하나를 두는 것이 전부라 레지스트리도 권한도 필요 없고 윈도우 판을 타지 않는다.
  한 단계 더 들어가는 것이 유일한 단점인데, 대신 여러 개를 골라 한 번에 보낼 수 있어
  미뤄 두었던 "파일 두 개 골라 비교" 가 덤으로 따라왔다.
  등록/해제할 때 예전 판이 레지스트리에 남긴 흔적도 같이 지운다.

  셸 확장 DLL 은 쓰지 않았다 - DLL 은 탐색기 프로세스 안에서 돌아 잘못되면 탐색기가 죽는다.

- GitWorkspace.RouteStartupArgs 가 요청을 화면으로 보낸다. 창이 다 만들어진 뒤에 탭을
  옮겨야 해서 ApplicationIdle 로 미루고, 요청 자체는 남겨 두어 늦게 만들어진 화면이
  스스로 집어 가게 했다(폴더 비교 쪽도 파일 비교와 같은 방식으로 추가).

- 곁들여: 파일 비교가 "양쪽 경로가 모두 있을 때만" 열리고 있었다. 셸은 하나만 줄 수도
  있으므로 한쪽만 있어도 열도록 고쳤다 - 없는 쪽은 빈 내용이 되어 전부 추가로 보인다.

ArgsTest 26건 신설. 전체 356건 통과.
실행 확인: 폴더 경로로 켜면 폴더 비교 탭에 그 폴더가 왼쪽에, 파일 두 개로 켜면 파일 비교
탭에 나란히. 등록 버튼을 누르면 보내기 메뉴에 항목이 생기고 버튼 이름이 "탐색기 보내기
해제" 로 바뀐다(실제 탐색기 메뉴에서 확인).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 17:25:42 +09:00