[전체 반영] 은 줄마다 Apply 를 따로 불러 바뀐 줄마다 머지 주석이 붙고 Undo 도
줄마다 한 걸음이었다. [구간 반영] 처럼 구간마다 주석 한 줄로 바꾼다.
- 두 파일 비교 [전체 반영]: 반영할 수 있는 줄이 이어진 구간(BlockAround 와 같은
기준)을 먼저 나눠 구간마다 ApplyGroup. 지우는 반영은 "삭제 N줄". 모든 구간을 한
묶음 번호로 넘겨 Undo 한 번에 전체가 돌아간다. ApplyGroup 에 group · finish 를 더함.
- 3-Way [전체 반영] 은 끈다(사용자 결정) - 차이 나는 모든 줄을 공통 조상(BASE)으로
바꾸던 동작이라 병합에서 쓸 데가 없고 양쪽 작업을 지운다. 꺼져도 툴팁으로 까닭.
- 3-Way [자동 병합] 도 저쪽만 고친 줄 구간마다 주석 한 줄 · Undo 한 번. 사이에 낀
충돌 · 내가 고친 줄은 구간을 끊고 그대로 둔다.
시험: 빌드 경고 0 · 오류 0. 화면 g22-accept-all(새) 주석 7 -> 3 · 삭제 2줄 ·
BASE 와 같음 · Undo 한 번, g23-three-way(새, --merge) 전체 반영 꺼짐 · 주석 5 -> 2 ·
내 줄 · 충돌 줄 그대로 · Undo 한 번. 실패 0. 기존 회귀는 사용자 지시로 돌리지 않았다.
Agent: main (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Accept 뒤 Alt+Down 을 두 번 눌러야 다음 차이로 가던 것 - 반영하며 캐럿 위에
주석 줄이 끼면 글자 수로 지킨 캐럿 자리가 그 주석 줄이 됐다. 주석을 끼우거나
빼기 직전 캐럿 행을 기억했다가, 글을 갈아 끼운 뒤 그 행의 편집기 줄에 캐럿을
둔다. 임시 기록으로 확인한 것: 글을 막 갈아 끼운 TextBox 의 줄 정보는 아직
옛 글 기준이다 - 줄 시작 자리는 새 글에서 직접 센다.
줄을 지우는 반영(BASE 에 없는 줄)에도 주석을 남긴다. 한 줄이면 "삭제",
구간 · 메서드로 여러 줄이면 한 번만 "삭제 N줄"(사용자 선택). 왼쪽으로 반영 ·
3-Way 저쪽 반영에도 같은 규칙.
색 구분 "줄 안에서 바뀐 부분" 에 줄 수를 붙였다(이 칸만 없었다).
타이핑: 1,806줄에서 재 보니 엔터마다 도는 재정렬 0.4초의 대부분이 목록에
1,800줄을 한 줄씩 넣으며 알림이 1,800번 가는 것이었다(파일 비교 자체 0.012초).
MergeLineCollection 으로 한 번에 넣고(ReplaceAll), 재정렬에서는 번호 말고 모든
값이 같은 줄은 기존 객체를 두고 번호만 고쳐 가운데만 빼고 넣는다(Patch,
MergeLine.SameStateExceptNumbers). 엔터 한 번 약 0.55초 -> 약 0.05초.
화면 요소 재활용(Recycling)은 효과가 없어 넣지 않았다.
탭이 20개를 넘어 오래 안 본 탭이 조용히 닫히면 알림을 띄운다.
시험: 빌드 경고 0 · 오류 0. 하네스 NoteTest 106 · PatchTest(새) 16.
화면 g12-note(주석 · 캐럿 · 되돌리기) · g14-inline · g15-typing-tabs(새 줄
제자리 · 번호 896 -> 897 -> 898, 21번째 탭에서 알림 · 20개 유지) 통과.
기존 회귀는 사용자 지시("방금 요청한 것만")로 돌리지 않았다.
Agent: main (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Git 탭에 폴더나 파일을 끌어다 놓으면 그 저장소를 연다. [폴더...] 와 같은 규칙을
PathUtil.RepositoryFolderFor 한 곳에 두었다 - 파일이면 그 폴더, 저장소 안이면
최상위, 저장소가 아니면 그 폴더 그대로(열기가 "저장소가 아니다" 를 알린다).
탭 전체에서 PreviewDrop 으로 받는다. 경로 칸 · 커밋 메시지 칸이 TextBox 라
파일 놓기를 먼저 먹고 버리는 문제를 폴더 비교(7차 E-2)에서 겪었다.
PathTest 6건을 먼저 넣어 실패 확인 -> 68건 통과. 흉내 낸 OLE 끌기는 이미 되는
폴더 비교 칸에도 들어가지 않아 도구 한계로 보고, 사용자가 직접 끌어다 놓아
확인했다(로그에 저장소 열기 두 번, 그 사이 단추 누름 없음).
파일 비교 편집 칸은 바탕이 없어 페이지 바탕(밝음 #F2F2F3 · 어두움 #23262B)이
비쳐 회색이었다. PaneBackgroundConverter 가 물려받은 글자색 밝기로 테마를 가려
밝음 #FAFAFA · 어두움 #252830 을 준다 - 후보를 실제 코드 색으로 그려 보여 주고
사용자가 골랐다. g11-pane 두 테마에서 빈 자리 화소로 확인.
하단 탭이 따라가지 않던 문제(폴더 비교 -> 두 번 눌러 파일 비교)는 공용 플랫폼
셸에서 고쳤다(MergeHub 코드 변경 없음, 기록만).
Agent: main (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
G-3 "덩어리" 를 "구간" 으로 - 단추 [구간 반영] · [구간 왼쪽으로], 단축키 설명, 로그.
G-4 저장 형식 콤보 둘을 구별 - 원본 인코딩 유지 · 원본 줄바꿈 유지. 저장값은
"원본 유지" 그대로(세션 보관본 7·8칸) - SaveChoice(Value, Label) 로 보이는 글만 가른다.
G-5 사내 문의처 받침값 - csproj <SupportContact> 를 실행 파일에 박는다(문구는 아직 비움).
G-6 설정 > 개발자 정보. 담당 카드는 Platform 최민영 대리 · MergeHub 김승준 사원,
소개 문구는 "사내 Merge/Diff + Git 도구"(Merge 먼저 - 창 제목 · csproj · 정보 창).
G-7 Alt+Down 화면 잘림 - 가운데 맞추기의 두 번째 스크롤이 메아리 막기에 걸려 버려졌다.
CenterCharInView 가 다른 칸을 직접 맞춘다(g7-verify 고치기 전 10건 실패 -> 0).
G-8 메모 문법 강조 · 같은 글 칠하기 · 색 마킹(Ctrl+1~5) · 위치 막대. 투명 TextBox +
아래층(사용자 결정). 화면에서 찾은 셋: 플랫폼 TextBox 스타일이 아래층을 덮음
(Style={x:Null}), 콤보에 형 이름(LanguageProfile.ToString), 어두운 테마에서 메모 탭 ·
문서 탭 제목이 검정(ItemContainerStyle 에 Foreground).
마무리(사용자 지시)
- 설정의 "프로그램 정보" 칸(만든 사람 · 사내 문의처)을 뺐다. [정보] 창은 실행 파일 값만.
- 주석 남기기가 켜져 있는데 작성자가 비면 반영 명령 맨 앞에서 알리고 반영하지 않는다
(예전에는 git 이름 · 윈도우 계정으로 조용히 채웠다). 주석을 끄면 묻지 않는다.
- 데모(설정 두 칸 · [데모 ->] 단추 · 전환 코드)를 걷어냈다.
시험: 빌드 경고 0 · 오류 0. 하네스 MemoHlTest 45 · MemoTest 69 · OverviewTest 15 ·
AboutTest 30 · NoteTest 99. 화면 최종 회귀 22벌 423건(실패 4건은 대본이 툴팁을
읽은 것 - 고쳐 통과), 마무리 뒤 g5 · g6 · g9-author 실패 0. 한 번 나오고 재현 안 된
g8 가로 스크롤 항목은 12차 기록에 "값으로 확정 못 함" 으로 남겼다.
Agent: main (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12차 B-1 로 왼쪽 파일로 반영하는 길([<] · TakeLineToBase)이 생겼는데 단축키가
없었다. 덩어리를 왼쪽으로 보내는 것은 명령 자체가 없었다 - AcceptBlock
(Alt+Shift+Right)은 오른쪽으로만 간다.
키를 어디에 둘지
사용자가 "Alt+Left 도 비어 있지 않냐" 고 물었다. 비어 있지 않았다 -
CopyRightToLeft 가 쓰고 있었는데, 2-Way 에서 그것이 하는 일은 이름·화살표와
달리 "이 줄 되돌리기" 였다. 그런데 이름이 가리키는 "왼쪽으로 반영" 이 B-1 로
실제로 생겼다. 그래서 감각이 맞는 쪽으로 넘겼다(사용자 결정).
Alt+Right 한 줄 오른쪽으로 그대로
Alt+Shift+Right 덩어리 오른쪽으로 그대로
Alt+Left 이 줄 되돌리기 -> 한 줄 왼쪽 파일로
Alt+Shift+Left (없음) -> 덩어리 왼쪽 파일로 (새로 만듦)
이 줄 되돌리기 Alt+Left -> 단축키 없음, Ctrl+Z 만
Alt+Right 가 이미 2-Way/3-Way 로 갈라져 있으므로 Alt+Left 도 같은 식으로
갈랐다. 3-Way(Take Theirs)는 안 건드렸다.
만든 것
- AcceptBlockToBase · ApplyGroupToBase - AcceptBlock/ApplyGroup 의 거울.
주석은 덩어리 첫 줄 위 한 줄, 되돌리기는 한 번에(11차 F-2 와 같은 규칙).
덩어리를 잡는 BlockAround 는 2-Way 에서 이미 CanTakeBase 로 잡으므로
그대로 썼다 - 가져올 수 있는 줄과 보낼 수 있는 줄이 같은 줄이고 방향만 반대다.
- [이 덩어리 왼쪽으로] 단추 - [이 덩어리 반영] 옆에. 두 파일 비교에서만 뜬다.
단축키만 두면 찾을 길이 없다.
겪은 것
- RaiseCanExecuteChanged 와 OnCaretRowChanged 에 새 명령을 안 넣어 단추가
꺼진 채였다. CommunityToolkit 커맨드는 CommandManager 를 구독하지 않는다.
- 덩어리 명령은 고른 줄이 아니라 CaretRow(편집기 캐럿)를 본다. 시험이 목록을
고르기만 해서 한 줄만 갔다 - Alt+Down 으로 캐럿을 놓아야 했다.
확인
- 화면 g2-verify 21건 실패 0 (연속 세 줄이 다른 재료를 따로 만들어 씀)
Alt+Left 는 한 줄만, Ctrl+Z 로 되돌아가고, 덩어리는 셋이 한 번에 가고
한 번에 돌아온다
- 하네스 ShortcutTest 88 -> 101건 (키 겹침 없음, 화살표 넷의 모양이 맞음,
충돌 이동을 안 빼앗음, Alt+Left 설명이 "되돌리기" 라고 거짓말하지 않음)
- 회귀 g1 · e2 · e3 · e4 실패 0, 빌드 경고 0 · 오류 0
값으로 확정하지 못한 것: Alt+Shift 조합을 흉내 낸 키로는 못 눌렀다. 윈도우가
입력 언어 전환으로 먼저 채간다 - SendKeys 로는 아예 안 닿고 keybd_event 로는
Shift 가 빠져 Alt+Left 처럼 동작했다. 기존 Alt+Shift+Right 로 견줘 봐도 같아
시험 도구 한계다(C-3 의 DragMove 와 같은 부류). 그래서 덩어리는 같은 명령을
부르는 단추로 확인했다. 사람 손으로 한 번 눌러 보는 것이 남았다.
Agent: main (claude-opus-5)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
짝을 바꾼 뒤 Ctrl+Z 를 누르면 앞 파일 글(234자)과 지금 파일 글(228자)을
끝없이 오갔다. 40번을 눌러도 안 끝났고, 글자를 하나도 안 쳐도 났다.
Ctrl+Z 는 우리 목록(_undo · _textUndo)이 비면 일부러 키를 먹지 않는다
(RunShortcut - 그래야 편집기의 글자 되돌리기가 살아 있다는 뜻이었다).
그러면 그 키가 TextBox 자체 되돌리기로 넘어가는데, WPF 의 그것은 한도가
없고 프로그램이 코드로 넣은 글까지 기록한다. 그래서 짝을 바꿔 새 파일을
실으면 그 글도 기록에 쌓이고, Ctrl+Z 가 앞 파일 글을 편집기에 되살렸다.
거기서 끝이 아니었다. 되살아난 앞 파일 글을 Reflow 가 "사용자가 친 것"
으로 보고 모델을 그쪽으로 되돌리며 되돌리기에 다시 쌓고 다시하기를 지운다.
다음 Ctrl+Z 는 우리 목록으로 되돌리고, 그러면 또 TextBox 것이 되살린다.
기록을 심어 고리를 떴다:
Sync 끝났다 편집기=228
편집알림 편집기=234 모델=216
Reflow 모델=216 편집기=221 같나=False
StepText 목표=216 … 편집기=234
221 = 234 - 13(줄 13개의 CRLF/LF 차이)이라 편집기가 쥔 것이 앞 파일임을
값으로 확인했다.
고침은 한 줄이다 - LocalEditor 에 IsUndoEnabled="False". 되돌리기는 우리
목록만 쓴다(줄 단위 _undo, 글 단위 _textUndo).
확인
- g1-verify 14건 실패 0. 30번을 눌러도 길이 자취가 228 하나뿐
- 앞 파일(234자)은 자취에 한 번도 안 나온다
- 되돌리기 자체는 살아 있다 - 친 글은 Ctrl+Z 로 되돌아간다
- 회귀 e1 · e2 · e2-reg · e3 · e4 전부 실패 0
- 빌드 경고 0 · 오류 0
헛짚은 것 둘도 기록에 남겼다. "문서가 바뀔 때 TextBox 기록을 비우면 된다"
(EditorUndoGate 를 만들어 하네스 16건까지 붙였다)와 "재정렬 타이머가 되돌린
뒤 뒤늦게 터진다" 는 둘 다 증상이 안 없어져 되돌렸다. 검증 안 된 동작
변경은 남기지 않는다.
남은 것: 글자 한 자 단위 되돌리기는 없어졌다. 이제 한 걸음은 "타이핑이
멈춘 자리" 다. 쓰다가 너무 굵으면 _textUndo 를 더 잘게 쌓는 것으로 따로 잡는다.
Agent: main (claude-opus-5)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자가 그림으로 짚어 준 것. 12차 B-1 로 넣은 [<] 단추가 든 칸의 폭이 Auto 여서,
단추가 보이는 줄에서만 칸이 벌어져 뒤 칸이 통째로 오른쪽으로 밀렸다.
같은 칸 안에서도 줄마다 글이 시작하는 자리가 달랐다.
BASE LOCAL
01 class Axis 01 class Axis
< 03 int speed = 100; 03 > int speed = 200; <- 밀림
< 04 // left only line 05 > < void Stop() { } <- 더 밀림
05 void Home() { } 06 }
BASE 는 [<] 가 맨 앞 칸이라 번호까지, LOCAL 은 번호 뒤 칸이라 코드가 밀렸고,
단추가 하나 늘 때마다 한 칸씩 더 밀렸다.
Visibility="Collapsed" 은 자리까지 없애므로, 자리를 지키려면 칸 폭이 고정이어야 한다.
- GutterBothWaysWidth 를 두어 BASE · LOCAL 이 같은 자리를 늘 잡아 둔다
- 화면이 모드에 따라 갈아 끼운다(ApplyGutterReserve) -
두 파일 비교는 단추 폭, Git 모드와 네 칸은 0(그 단추가 아예 없다 - 여백이 예전 그대로)
- 투명한 편집기가 아래 표시층과 어긋나면 캐럿이 글자와 다른 자리에 선다 -
EditorGutterMargin 도 같은 값만큼 민다
- 글자 크기(11차 F-5)를 바꾸면 단추 폭이 따라 바뀌므로, 잡아 두는 자리도
CodeFontMetrics 한 벌에서 나온다
화면으로 확인: 한 칸의 모든 줄이 같은 x(BASE 137 · LOCAL 1283),
글자 크기를 키워도 한 x(147), Git 모드도 한 x(459). 오류 글 0.
E-2 화면 세 벌 · 왼쪽 번호 한 벌 모두 그대로 통과. 빌드 경고 0 · 오류 0.
남겨 둔 것: BASE 줄 끝의 [>](11차 F-10)는 아직 Auto 다. 왼쪽 가장자리를 밀지 않고
오른쪽에서 코드 칸을 조금 좁힐 뿐이라 눈에 띄지 않는다. 워드랩을 켜면 그 줄만
접히는 자리가 달라질 수 있다 - 워드랩은 기본이 꺼짐이라 이번에는 두었다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
새 플랫폼(UbisamBase.Launcher) 위로 옮기면서 12차 A~E 를 한 번에 담는다.
항목별 값과 판정은 doc/history/2026-09-23-12차.md, 요약은 doc/history/changelog.md.
A. 폴더 비교를 읽기 쉽게
- A-1 폴더 줄의 크기가 늘 0B 이던 것 - 안에 든 파일 크기 합계를 아래에서 위로 더해 적는다
(걸러 낸 파일은 합계에서도 빠진다)
- A-2 좌우로 나눠 보이기 - 왼쪽 · 오른쪽 목록을 나란히 두고 같은 줄에 맞춘다.
한쪽에만 있는 항목은 반대편을 비운다
B. 파일 비교 화면
- B-1 2-Way 에서 양쪽으로 머지 - 칸마다 반영 · 저장. 왼쪽 기준점을 따로 세고,
되돌리기 · 저장 백업도 양쪽 모두
- B-2 프로그램 정보 창 - 버전 · 빌드 날짜 · 만든 사람 · 사내 문의처 · 플랫폼 버전 · 로그 폴더
- B-3 칸 아래에 무엇이 달라졌는지 - 칸마다 줄 수 · 추가 · 삭제 · 수정, 가운데에 진행
C. 플랫폼 (플랫폼 저장소에서 함께 나감)
- C-2 하단 탭 줄을 한 단계 작게 - 74 -> 61 DIP. 실측 133 -> 109px 이고
그만큼 코드 칸이 늘어 파일 비교가 47 -> 48줄
E. 저장하지 않아도 남는 편집
- E-2 여러 짝을 동시에(문서 탭). 지금까지는 한 짝만 들어서 짝을 바꾸면
저장하지 않은 편집을 묻고 버리면 사라졌다(재현: 16줄 -> 15줄).
이제 떠 있던 탭이 그 글을 맡아 두므로 묻지 않는다.
- 탭마다 HomeViewModel 을 따로 만들지 않았다 - 이 화면은 GitWorkspace 의 여러 사건과
한 자리짜리 약속(ConfirmDiscardEdits · ConfirmLeaveCommit)에 물려 있다.
화면은 하나로 두고 탭이 파일에 없는 것만 맡는다(고친 글 · 왼쪽 글 · 되돌리기 이력 ·
두 기준점 · 캐럿 · 스크롤 · 저장 형식)
- 탭 이름은 파일 이름, 다르면 왼 <-> 오. 양쪽이 같은 부분은 한 번만 적는다
(WeldController_기준 <-> 내작업.cs, 421 -> 288px). 같은 이름이 겹치면
갈릴 때까지 위 폴더를 한 겹씩 덧붙인다
- 저장하지 않은 탭에 가운뎃점. 사람이 손댄 것만 센다 - 중괄호 맞춤으로만 바뀐 것은
묻는 자리와 같은 기준으로 뺀다(안 그러면 .cs 를 여는 것만으로 늘 점이 붙는다)
- 탭이 사라져도 고친 글은 보관함에 남아 다시 열면 되살아난다(짝 50개).
E-1(껐다 켜도 남는 편집)은 이 보관함을 파일로 옮겨 적으면 된다
- 이전 · 다음 파일은 지금 탭의 짝만 바꾸고, 폴더 비교에서 두 번 누르면 새 탭(사용자 결정)
- Ctrl+Tab · Ctrl+Shift+Tab · Ctrl+W · 가운데 단추 닫기. 닫을 때도 묻지 않는다
- Git 탭 · 병합 중 네 칸은 탭이 맡지 않는다 - 그쪽은 예전처럼 묻는다
하네스 27벌 1,787건 통과 · 실패 0(DocTabTest 106건 새로 만듦).
빌드 경고 0 · 오류 0. 화면으로 E-2 34건 · 회귀 19건 확인.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 정렬 행은 그대로 두고 칸마다 그 칸에 있는 줄만 걸러 보임(빈 줄로 맞추지 않음), 칸마다 자기 행 높이
- 편집기에서 빈 줄 없앰(StripFillers 삭제), 편집기 줄 <-> 정렬 행 표(EditorSnapshot.Rows)
- 스크롤은 가운데 기준으로 따라옴(PaneMapping), 차이 이동은 그 자리를 가운데로
- 틈에 바뀐 덩어리 사다리꼴 선 · 경계선 · 옮김 점선(PaneLinkOverlay), 3분할은 위 세 칸 사이
- 지운 줄 되살리기 [>] 는 BASE 칸 끝
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 설정 "저장할 때 백업"(기본 끔). 켜면 모든 저장 직전 지금 파일을 바이트 그대로 {설정 폴더}\Backup\MergeHub\날짜\... 로 복사(FileBackup)
- 두 파일 · mergetool · Save & Commit · 병합 중 Save · 파일 단위 Accept(IGitService.BeforeOverwrite) · 폴더 비교 복사
- 날짜 폴더마다 목록.txt, 저절로 지우지 않음, 못 만들면 저장하지 않음, ACTIONS [백업 폴더 열기]
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 사용자 결정: 줄 간격만 줄이고 선택 사항(단추 · 설정)은 만들지 않음
- 12 → 16, 1920x1080 두 칸 40 → 50줄, 네 칸 17 · 18 → 22 · 23줄
- 북마크 표식 높이도 줄에 맞춤
- FontTest 144(1,572건), E-1 회귀 없음
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 한 값을 모든 모니터에(모니터 배율은 플랫폼), 코드 칸만(사용자 결정)
- CodeFontMetrics: 줄 높이 · 번호 칸 · 여백 단추를 같은 비율로, 12 에서 지금 값 그대로
- 화면은 DynamicResource 한 벌, MergeLine.MinimumRowHeight 도 따라감
- Ctrl+휠 · Ctrl++/- · Ctrl+0 · 설정 "보기 > 코드 글자 크기" · 상태 줄 글자 N
- 줄 번호 기준선을 코드와 맞춤
- FontTest 110 · ShortcutTest +14(1,538건)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 위 상태 바 [ACTIONS 감추기 ▶ (F9)], 단축키 표 F9. 칸 · 구분선 폭 0, 펴면 끌어 둔 폭 그대로
- 설정 ActionsHidden 에 기억. 감춘 채 Ctrl+S · Alt+←/→ 그대로
- 덧(사용자 요청): 아래 탭 줄 접기는 플랫폼에 넣음(배포 전)
- 1440p 150%: 코드 칸 폭 +163px · 높이 +71px. ShortcutTest +3
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- [이 메서드 반영]: 캐럿이 놓인 클래스 멤버를 통째로(사용자 결정: C# + C/C++,
메서드 · 생성자 · 속성 · 이벤트 · 연산자 · 필드 · enum, 로컬 함수 안이면 감싸는 멤버)
- MemberRanges: Roslyn 없이 주석 · 문자열(축자 · 보간 · raw · C++ raw · 숫자 구분자)을
가리고 #if 갈래마다 다시 읽어 중괄호 짝으로 범위. 못 잡으면 단추를 끄고 까닭 한 줄
- 덩어리 · 메서드 반영(ApplyGroup): 머지 주석 한 줄(메서드 이름 위 · 덩어리 첫 줄 위),
로그 한 줄, Undo · Redo 한 번(LineEdit.Group). 덩어리가 줄마다 주석을 달던 것도 고침.
주석만 든 편집(NoteOnly)은 직접 수정 · 편집 수에 안 셈
- 메서드 반영 저장본 = 같은 줄 줄 단위 반영 저장본(바이트). MemberTest 83건(23벌 1,395건)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 칸 이름 LOCAL(Mine) · REMOTE(Theirs)(사용자 결정: 표준 용어 + 영문 쪽 이름)
- 칸 머리마다 한 줄 "어느 쪽 · 어느 파일"(PaneHeaders). MERGED · 두 칸 LOCAL 은
"(저장할 파일)", mergetool · --merge 는 제 임시 파일 이름 - Mine 칸이 MERGED 이름을
보이던 것(MineHeader) 고침. 좁으면 가운데를 줄이고 툴팁에 전체(MiddleTrim)
- 머지 주석 [사람] 날짜 출처 설명(사용자 결정: 쪽 이름 + 브랜치/해시, 출처 먼저).
출처는 로그와 같은 말 - 두 칸 로그 BASE(해시) 반영, 브랜치 3-Way 로그 REMOTE(브랜치) 반영
- Take Mine 도 주석(처음 한 번, 되돌리면 함께 빠짐)
- 무시 조건은 [사람] 날짜 뒤를 따지지 않아 코드 그대로 - 옛 · 새 · 출처만 다른 주석을
하네스로 굳힘(NoteTest · RulesTest · FolderTest · MergeSaveTest, 1,312건)
- 네 길 화면 확인 · E-1 병합 길 회귀 없음
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Take Theirs 로그가 3-Way 콤보 값을 써서 "10행 (3-Way 안 씀) 반영" 이었고, Take Mine 은 로그가 없었다.
이제 "10행 Theirs(feature/theirs) 반영" · "10행 Mine(feature/mine) 으로 정함".
충돌 네 칸이면 3-Way 콤보 대신 "병합 충돌 · REMOTE = 상대". 브랜치 3-Way 문구는 그대로.
MergeSaveTest 82건 통과.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LOCAL 칸을 이 파일에만 쓰고 스테이징하는 단추라 Save & Commit 과 짝이 되게 이름만 바꿈.
알림 · 막힘 안내 · 웹 문서도 Save. 하는 일은 그대로(충돌 24 → 23, 커밋 없음 확인).
7차 지시서: 6차 D-1 에서 걸린 세 가지(마지막 저장 뒤 남은 차이 · 로그 3-Way 안 씀 · 기록 파일 남음)와
pull · rebase · cherry-pick 충돌.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
상대가 지운 파일(UD)이나 내가 지운 파일(DU)을 열면 줄 단위 3분할로
끌고 가서 지운 쪽 칸이 통째로 비었다. 범례는 내 쪽에만 있는 줄 89개를
"Theirs only 89" 라고 거꾸로 말했고, 정할 것인 "남길까 지울까" 는
화면 어디에도 없었다. 파일 단위 해결은 이미 바르게 동작했다.
- DeletionConflict: 어느 쪽이 지웠는지, 남기기와 지우기가 각각 어느
쪽을 고르는 것인지(UD 는 남기기=내 것, DU 는 남기기=상대 것)
- LoadFileAsync: 지운 충돌이면 남은 파일을 BASE 와 두 칸으로 보인다.
칸 제목이 누가 지웠는지 말하고, BASE 제목은 (merge base)
- 범례 위 띠: 누가 지웠고 누가 고쳤는지, [파일 남기기] [파일 지우기]
- 남기기는 고친 것이 있으면 고친 대로 남기고, 지우기는 고친 것이
있으면 한 번 묻는다. 푼 뒤 남은 충돌 첫 파일로 간다
- 해결로 저장과 같은 뒷정리를 ReloadAfterResolveAsync 로 모았다
시험 저장소 생성기에 DU 경우를 넣었다(충돌 23개). 뿌리 폴더를 잡고
있는 셸 때문에 다시 만들기가 멈춰서 안만 비우게 고쳤다.
화면 확인 23건 + BASE 제목 고친 뒤 5건 통과. MergeSaveTest 16건 추가.
21벌 775건 통과(새로 빌드한 실행 파일). 경고 0, 오류 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
경로 칸(TextBox)이 Drop 을 먼저 먹어 놓아도 아무 일이 없었다 - Preview 로 옮겼다.
파일 비교의 경로 글자는 Background 가 없어 놓을 자리 자체가 없었다.
칸에 놓아도 다시 견주지 않던 것을 DropFile / DropFolder 로 고쳤다.
파일을 하나씩 놓아 짝을 만들 수 있게 했다.
검색 결과 칸에 머리글을 넣고 줄 간격을 목록과 맞췄다.
결과를 남에게 보내거나 결재에 붙일 때 화면을 캡처하는 것 말고는 방법이 없었다.
캡처는 검색도 안 되고 줄 번호를 짚어 말하기도 어렵다.
Services/CompareReport.cs 신설. 파일 비교와 폴더 비교 양쪽에서 쓴다. 글을
만드는 일만 여기서 하고, 어디에 저장할지 묻는 것은 화면 쪽 일이다. 그래야
화면 없이 검사한다.
파일 쪽은 요약과 다른 줄 목록을 적는다. 줄 번호는 양쪽을 다 적는다. 한쪽에만
있는 줄이 있어 번호가 어긋나므로 하나만 적으면 파일에서 그 줄을 찾을 수 없다.
폴더 쪽은 상태와 상대 경로를 줄마다 적는다. 폴더 자체는 적지 않는다. 그 안의
파일이 이미 다 적혀 있다.
곁들여 요약에 주석만 다른 수를 덧붙였다. "다름 3(주석만 1)". D-1 로 새로 생긴
갈래가 요약에는 안 보였다.
확인: 두 화면에서 각각 뽑아 메모장으로 열었다. ReportTest 23건 신설.
전체 451건 통과.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
C-1. 코드 위에 마우스를 올리면 그 줄 내용이 그대로 툴팁으로 다시 떴다. 글이
이미 보이는데 같은 글이 상자로 겹쳐 뜨니 가리기만 한다. 원본 세 칸에서 뺐다.
버튼과 상태 아이콘 툴팁은 그대로 둔다. 그쪽은 화면에 없는 정보를 알려 준다.
C-2. Git 탭 목록의 글자가 ... 없이 중간에서 뚝 끊겼다. 줄임표 설정은 이미
있었는데 듣지 않았다. 목록의 가로 스크롤이 켜져 있으면 항목이 제 글 길이만큼
넓게 잡히고, 그러면 잘릴 일이 없으니 줄임표도 나오지 않는다. 가로 스크롤을
끄면 항목이 칸 너비에 갇히고 그때 비로소 줄임표가 나온다. 커밋/변경 파일/
브랜치/충돌/태그/서브모듈 여섯 목록에 같이 걸었다.
"작업 취소" 버튼과 Git 탭 입력 칸이 잘리는 것은 재현하지 못했다. 2560x1600 과
1920x1080 에서 배율 100%/120% 로 여섯 하위 탭을 모두 봤지만 멀쩡했다.
C-3. 폴더 복사 확인 창을 윈도우 기본 대화상자에서 플랫폼 것으로 바꿨다.
글꼴도 색도 배치도 혼자 달라 "이 프로그램이 묻는 것"으로 읽히지 않았다.
묻는 것 자체는 없애지 않았다. 복사/삭제는 되돌릴 수 없다.
확인: 코드 위 3초 머물러도 툴팁 없음. 이력 목록이 ... 로 줄어듦. 폴더 복사
확인 창과 완료 토스트가 프로그램의 다른 알림과 같은 모양.
테스트 399건 그대로 통과.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
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>
"줄 단위로 비교할 수 없습니다" 한 줄로 끝내면 정작 알고 싶은 "같은지 다른지" 를
모른 채 화면을 닫게 된다. 답이 있는 화면으로 바꿨다.
- 크기 · SHA-1 · 처음 갈리는 바이트 위치를 한 줄로 알려 준다. 크기가 같아도 내용이
다를 수 있어 해시로 본다. 앞부분이 같고 길이만 다르면 짧은 쪽이 끝나는 자리가
갈리는 지점이다.
- 그림(.png/.jpg/.bmp/.gif/.ico/.tif)이면 나란히 띄운다 - 16진으로 보는 것보다 훨씬 빠르다.
- 그 밖에는 앞 4KB 를 16진으로 나란히 놓고, 16바이트 단위로 다른 줄에만 색을 준다.
볼 수 있는 글자는 오른쪽 칸에 그대로 적는다 - 16진만 보면 무슨 파일인지 모른다.
수십 MB 짜리를 전부 그리면 화면이 굳으므로 앞부분만 그리고 잘렸다고 알린다.
BinaryTest 25건 신설(같음·가운데 다름·길이 다름·16진 표기·줄 수 제한·글자 칸·
없는 파일·그림 판별). 전체 330건 통과.
실행 확인: .bin 두 개 -> "다릅니다 · 왼쪽 17 B · 오른쪽 19 B · 처음 갈리는 곳 0x10"
+ 16진 두 줄(0x10 줄만 색). .png 두 개 -> 나란히 표시.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 바꾸기: 찾기 칸 아래에 바꿀 말 줄이 붙는다. Ctrl+F 로 열면 안 뜬다 -
찾기만 할 때 자리를 뺏지 않기 위해서다. "바꾸기" 는 고른 자리가 찾는 말일 때만
바꾸고 다음으로 넘어간다 - 엉뚱한 자리를 덮어쓰는 것보다 한 번 더 누르게 하는 편이 낫다.
"모두" 는 한 번에 바꾸고 몇 개인지 알려 준다(되돌리기는 편집기의 Ctrl+Z 가 맡는다).
- 덩어리 단위 반영: 줄 하나씩만 되면 연속 다섯 줄을 다섯 번 눌러야 한다.
WinMerge·Beyond Compare 가 덩어리를 기본 단위로 쓰는 이유다. 덩어리는
"차이로 잡힌 줄이 이어지는 구간"이고, 캐럿이 그 안에 있을 때만 켜진다. Alt+Shift+→.
- 저장 형식: 사내 소스에 CP949 로 저장된 파일이 섞여 있어 새로 만드는 파일과 형식이
갈린다. 읽어서 보여 주기만 하면 그 갈림을 못 고치므로 저장할 때 고를 수 있게 했다.
기본값 "원본 유지" 라 지금까지와 동작이 같다. Save & Commit 경로도 같은 값을 쓴다
(전에는 File.WriteAllText 로 UTF-8 고정이었다).
실행 확인: PulseUs → PulseMicros 2개 바꿈 · 마지막 차이에서 2줄 한 번에 반영.
단축키 61 → 63건, 전체 305건 통과.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
지금까지는 안 겹치는 변경까지 사람이 하나씩 눌러야 해서, 정작 판단이 필요한
서너 줄이 그 속에 묻혔다. git merge 가 자동으로 해 주는 일을 여기서도 해 준다.
- 자동 병합: 저쪽만 고친 줄(ThreeWayState.RemoteChanged)을 한 번에 가져온다.
충돌과 내가 고친 줄은 건드리지 않는다. 이미 가져온 줄은 더 이상 RemoteChanged 가
아니므로 여러 번 눌러도 안전하다.
- 충돌만 이동: Alt+Shift+↑↓. "다음 차이" 와 달리 아직 안 정한 충돌만 딛는다.
- 완료 판정: ACTIONS 에 "남은 충돌 N개"(빨강) → "충돌 정리 끝"(초록).
판단이 하나 필요했다 - 충돌 여부는 BASE·MINE·REMOTE 를 견주면 저절로 나오지만,
"내 것으로 간다"고 정한 줄은 내용이 그대로라 여전히 충돌로 보인다. 그래서
MergeLine.NeedsDecision(충돌이면서 반영·수정 표시가 없는 줄)을 따로 두었다.
그 결정은 글을 바꾸지 않아 편집 뒤 재정렬하면 사라지므로, 얼어 있는 BASE 줄 번호
(없으면 MINE 줄 번호)로 붙들어 되살린다.
곁들여 고친 것: Take Mine / Take Theirs 버튼이 줄을 옮겨도 켜짐·꺼짐이 그대로였다.
CommunityToolkit 커맨드는 CommandManager 를 구독하지 않는데 이 둘만 갱신 목록에서
빠져 있었다 - 키보드(Alt+←/→)로는 되고 버튼만 안 되던 이유다.
실행 확인(mergehub-demo, 3-Way = feature/cooling): 자동 병합으로 Theirs only 1→0,
다음 충돌+Take Theirs 를 반복해 남은 충돌 3→2→1→"충돌 정리 끝".
테스트 290 → 293건 전부 통과(단축키 3건 추가).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
UbisamBase 플랫폼 위에서 도는 플러그인. 지금까지 만든 것을 그대로 담는다.
- 폴더 비교 / 파일 비교(부분 수용·워드랩·찾기) / 3-Way 병합 / Git 조작
- 비교 엔진: histogram 정렬 · 이동 블록 감지 · 무시 규칙 · 13개 언어 토크나이저
- doc/ 에 작업 지시서와 진행 기록
빌드 산출물(bin/obj)은 추적하지 않는다 - 플랫폼 런타임이 빌드 때마다
D:\UbisamPlatform\bin 에서 복사되어 들어오므로 저장소에 담을 이유가 없다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>