59 Commits

Author SHA1 Message Date
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
49a05a0628 밖에서 부르기: 명령줄 인자 수신 · 탐색기 우클릭 등록
git config 에 mergetool/difftool 로 등록하는 쪽은 전부터 있었는데 정작 그 인자를
받는 쪽이 없어 다리가 반만 놓여 있었다. 나머지 반쪽을 놓는다.

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

- Services/ShellIntegration: 탐색기 우클릭 메뉴를 파일·폴더·폴더 배경 세 자리에 넣는다.
  HKEY_CURRENT_USER 에만 쓰므로 관리자 권한이 필요 없고, 지울 때도 이 사람 것만 지운다 -
  사내 PC 에 권한 없이 깔리는 것이 전제다. 셸 확장 DLL 을 만들지 않은 것도 같은 이유로,
  DLL 은 탐색기 프로세스 안에서 돌아 잘못되면 탐색기가 통째로 죽는다.
  폴더 배경에서는 %1 이 아니라 %V 가 그 폴더다.

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

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

ArgsTest 26건 신설. 전체 356건 통과.
실행 확인: 폴더 경로로 켜면 폴더 비교 탭에 그 폴더가 왼쪽에, 파일 두 개로 켜면
파일 비교 탭에 나란히. 등록 버튼을 누르면 레지스트리 3개 키가 생기고 버튼 이름이
"탐색기 우클릭 해제" 로 바뀐다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 16:56:56 +09:00
55d9deb418 이진 파일·그림 비교 (Services/BinaryCompare)
"줄 단위로 비교할 수 없습니다" 한 줄로 끝내면 정작 알고 싶은 "같은지 다른지" 를
모른 채 화면을 닫게 된다. 답이 있는 화면으로 바꿨다.

- 크기 · 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>
2026-09-08 14:50:11 +09:00
de1a43cc70 파일 비교: 바꾸기(Ctrl+H) · 덩어리 단위 반영 · 저장 형식 고르기
- 바꾸기: 찾기 칸 아래에 바꿀 말 줄이 붙는다. 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>
2026-09-08 14:44:08 +09:00
524a6a715d 폴더 비교: 폴더째 복사·삭제 · 보기 필터 · 비교 취소
비교만 되고 정리는 안 되던 화면이었다. 셋을 채워 "보고 → 고르고 → 맞춘다" 까지 닫는다.

- 폴더째 복사·삭제: 파일 하나씩만 되던 것을 폴더에도 열었다. 확인 창에 안에 든
  파일 수를 적는다 - "폴더 하나"라고만 물으면 몇 개가 덮이는지 모르는 채 확인을
  누르게 된다. 복사는 겹치는 파일만 덮고 대상에만 있던 파일은 남긴다(동기화가 아니다).
- 보기 필터: 다른 것만 / 전체 / 왼쪽에만 / 오른쪽에만 / 같은 것만.
  다시 비교하지 않고 마지막 결과로 목록만 다시 그린다 - 큰 폴더를 다시 훑는 것은
  필터를 만지는 값으로 너무 비싸다. 기존 "같은 파일도 보기" 체크는 이 필터가 대신한다.
- 비교 취소: FolderComparer.Compare 에 CancellationToken 을 넣고 항목마다 확인한다.
  누르는 즉시 멈추고, 앞서 본 결과는 그대로 둔다(실패가 아니라 사용자의 결정이다).

설계 하나 - 파일을 실제로 옮기고 지우는 부분을 Services/FileOps.cs 로 뺐다.
되돌릴 수 없는 일이라 화면 없이 검사할 수 있어야 한다.

실행 확인: sub(파일 2개) 폴더째 복사 → b\sub\deep\two.txt 까지 따라옴.
목록 15개 → "왼쪽에만" 5개(요약 줄은 그대로 = 다시 비교하지 않음).
FolderTest 27 → 37건(취소 3 · 파일 세기 2 · 폴더 복사 5). 전체 300건 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 11:20:55 +09:00
85c5e9e085 3-Way 를 "끝낼 수 있게" 만들기 (자동 병합 · 충돌만 이동 · 완료 판정)
지금까지는 안 겹치는 변경까지 사람이 하나씩 눌러야 해서, 정작 판단이 필요한
서너 줄이 그 속에 묻혔다. 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>
2026-09-08 10:49:28 +09:00
9956567bf8 Git 탭에 다섯 기능 추가 (amend · stash 목록 · 커밋 간 비교 · blame · 변경분 추출)
기획안 4p 의 "Git 조작" 항목 중 화면에 없던 것들을 채웠다. 다섯 중 넷은
GitService 에 이미 구현돼 있었고 버튼만 없던 것이라, 서비스를 새로 만든 것은
변경분 추출 하나뿐이다.

- 커밋 수정(amend): 오타 난 메시지나 빠뜨린 파일을 새 커밋을 쌓지 않고 바로잡는다.
  고쳐 쓸 메시지를 처음부터 다시 치지 않게 "마지막 메시지" 버튼을 곁들였다.
- stash 목록: 저장/적용만 있어 "맨 위 것"에만 손이 닿았다. 골라서 적용·삭제한다.
  하나 꺼내면 번호가 한 칸씩 당겨지므로, 목록이 바뀌면 고른 항목을 다시 잡는다 -
  안 그러면 다음 삭제가 엉뚱한 것을 지운다.
- 두 커밋 사이 비교: "여기부터" 로 시작점을 잡으면 그 뒤 고르는 커밋이 끝점이 된다.
  안 잡으면 지금까지처럼 부모와 비교한다(기존 동작 유지).
- blame: 머지 중에 "이 줄 왜 이렇게 됐지"를 묻게 되는데, 이력을 뒤지는 것보다 빠르다.
- 변경분 파일 추출: 장비에 소스를 통째로 넣지 못하는 현장에서 바뀐 것만 들고 갈 때 쓴다.
  텍스트로 다시 쓰면 줄바꿈과 인코딩이 바뀌므로 바이트 그대로 옮긴다.

곁들여 고친 것: 상태 배지 줄의 ItemHeight 가 24 로 묶여 있어 "mergetool 등록"
버튼이 반쯤 잘려 보였다. 줄 높이는 내용이 정하게 두었다.

실행 확인(데모 저장소): 메시지 수정으로 sha 가 바뀜 · stash 저장→목록→적용으로
워킹트리 복구 · 헤더가 "2766bc5 → 6e6bb78 (2개 파일)" · blame 31줄 전부 표시 ·
변경분 2개 파일 추출.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 10:35:45 +09:00
a0ec7174a1 진행 상황 문서 신설
작업 하나가 끝날 때마다 상태를 고치고 커밋한다. 대기/진행/완료로 구분해
"지금 어디까지 왔나"를 한 눈에 본다.

이번 주는 폭을 넓히는 주다 - 한 덩어리를 깊게 파는 대신 Git 조작·3-Way·
폴더 비교·파일 비교를 각각 "있다"고 말할 수 있는 선까지 올린다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 10:14:09 +09:00
7719094edf 최초 커밋: MergeHub (사내 Git Merge/Diff 도구)
UbisamBase 플랫폼 위에서 도는 플러그인. 지금까지 만든 것을 그대로 담는다.
- 폴더 비교 / 파일 비교(부분 수용·워드랩·찾기) / 3-Way 병합 / Git 조작
- 비교 엔진: histogram 정렬 · 이동 블록 감지 · 무시 규칙 · 13개 언어 토크나이저
- doc/ 에 작업 지시서와 진행 기록

빌드 산출물(bin/obj)은 추적하지 않는다 - 플랫폼 런타임이 빌드 때마다
D:\UbisamPlatform\bin 에서 복사되어 들어오므로 저장소에 담을 이유가 없다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 10:13:27 +09:00