# 11차 진행 기록 (2026-09-18 ~) 지시서: [../작업지시/11차.md](../작업지시/11차.md) ## A-1. 변경분 추출을 먼저 뽑아 보고 적는다 (2026-09-18, 완료 · 고치지 않음) 지시서대로 **고치지 않고 적기만 했다.** 제품 코드는 바꾸지 않았다. ### 무엇으로 했나 - `C1Repo` 로 저장소를 새로 만든 뒤 `e11-a1-setup.sh` 로 추출 시험용 커밋을 더 쌓았다(전부 지어낸 파일). | 커밋 | 무엇 | |---|---| | `4eb9ece` base | 내 쪽 작업 (C1Repo 의 feature/mine) | | `d3eb15b` c1 | 새 파일 `Extract/Temp.cs` · `Io/Unit12.cs` 한 줄 더함 | | `f884ed1` c2 | `Recipe/Unit11.cs` 지움 · `Motion/Unit16.cs` → `Motion/Renamed16.cs`(내용 그대로) · 이진 `Extract/logo.bin` · `한글폴더/깊은/경로/아래/설명.cs` | | `cbcad8a` c3 | `Io/Unit12.cs` 를 c1 전으로 되돌림 · `Extract/Temp.cs` 지움 (범위 안에서 생겼다 사라짐) | | `f702996` side · `58d5f7f` merge | base 에서 갈라진 옆가지에 `Side/SideOnly.cs`, 그것을 `--no-ff` 로 병합 | - 화면은 사람 순서로: Git 탭 → 이력에서 줄을 **마우스로** 고르고 [여기부터] · [해제] · [변경분 추출], 폴더 창에는 경로를 쳐 넣고 Enter. - 뽑은 폴더는 `git diff -M --name-status` 의 기대 목록과 견주고, 파일마다 `git hash-object --no-filters` 로 **바이트(blob 해시)** 를 대조했다. ### 아홉 경우의 결과 | # | 경우 | 알림 | 뽑힌 것 | git 과 견주면 | |---|---|---|---|---| | 1 | 커밋 하나(시작점 없음, c1) | "2개 파일 추출" | `Extract/Temp.cs` · `Io/Unit12.cs` | **같음** · 바이트 같음 | | 2 | 범위 [여기부터] base → c3 | "3개 파일 추출 (삭제되어 건너뜀 1개)" | `Extract/logo.bin` · `Motion/Renamed16.cs` · `한글폴더/…/설명.cs` | **같음** — 범위 안에서 생겼다 사라진 `Temp.cs`, 바뀌었다 되돌아온 `Unit12.cs` 는 **들어가지 않는다**(맞다) | | 3 | 지운 파일이 있는 범위 | 위와 같은 알림 | — | 건너뛴 **개수만** 알린다. `Recipe/Unit11.cs` 라는 것은 **화면 · 로그 · 폴더 어디에도 없다** | | 4 | 이름 바뀐 파일 | — | `Motion/Renamed16.cs` (새 이름) | 새 경로로 바이트 그대로. **옛 경로(`Motion/Unit16.cs`)를 알 길이 없다** — 장비에 덮어 넣으면 옛 파일이 남는다 | | 5 | 병합 커밋 하나(merge) | "1개 파일 추출" | `Side/SideOnly.cs` | **첫 부모(c3)와만** 견준다. 둘째 부모(옆가지)와 견주면 4개인데, 지금 무엇과 견주는지는 화면에 없다 | | 6 | 거꾸로 범위 [여기부터] c3 → base | "2개 파일 추출 (삭제되어 건너뜀 2개)" | `Motion/Unit16.cs` · `Recipe/Unit11.cs` | git 의 `diff c3 base` 와 **같음**(되돌리는 방향으로 동작). **경고나 방향 표시는 없다** | | 7 | 이진 · 한글 · 깊은 경로 | 2 와 같음 | `logo.bin` 278B · `설명.cs` 50B | **바이트 · 경로 그대로** | | 8 | 이미 파일이 있는 폴더 | "3개 파일 추출 (삭제되어 건너뜀 1개)" | 폴더 안 **6개** | 묻지 않고 덮어쓴다. 앞서 뽑아 둔 `Extract/Temp.cs` · `Io/Unit12.cs`(c1 것)와 사람이 넣어 둔 `사용자메모.txt` 가 **그대로 남아 섞인다** | | 9-a | 대상 파일이 읽기 전용 | **"변경분 추출 실패: … 액세스가 거부되었습니다"** | 2개(logo.bin + 읽기 전용 그대로) | **반쯤 뽑힌 채 멈춘다** — 앞 순서 `logo.bin` 은 써졌고 뒤 순서 `한글…설명.cs` 는 빠졌다. 몇 개까지 됐는지는 알림에 없다 | | 9-b | 대상 파일이 다른 프로그램에 열려 있음 | **"… 다른 프로세스에서 사용 중이므로 …"** | 2개 | 9-a 와 같은 모양 | - 알림과 같은 글이 Git 탭 로그에도 남는다 — 성공은 `변경분 추출: N개 파일 → 경로 (삭제되어 건너뜀 M개)`, 실패는 `[변경분 추출] 실패: …`. - 범위 표시는 제대로 바뀐다: 시작점이 없으면 `부모 → 고른 커밋`, [여기부터] 를 누르면 `4eb9ece → 고른 커밋`. - 폴더 창은 늘 **저장소가 있는 폴더**에서 열린다. - 저장소 워킹트리는 아홉 경우 내내 Clean 이었다(추출은 읽기만 한다). ### 이걸로 확정된 것 (A-2 ~ A-4 로 넘긴다) | 번호 | 확정된 문제 | 어디로 | |---|---|---| | ① | 지운 파일 · 이름 바뀐 옛 경로가 결과에 남지 않는다(경우 3 · 4) | **A-2** | | ② | 무엇과 무엇 사이를 뽑았는지 폴더에 남지 않는다(경우 5 · 6 — 병합 커밋은 첫 부모, 거꾸로 범위도 말없이 됨) | **A-2** | | ③ | 비어 있지 않은 폴더에 묻지 않고 덮어쓰고 옛 파일이 섞인다(경우 8) | **A-3** | | ④ | 쓰다 막히면 반쯤 뽑힌 채 멈추고, 어디까지 됐는지 알 수 없다(경우 9-a · 9-b) | **A-3 에 덧** — 먼저 쓸 수 있는지 보고 시작할지, 실패해도 나머지를 계속할지 정한다 | **맞게 도는 것**(고칠 것 없음): 파일 고르기(1 · 2 · 5 · 6 모두 git 과 같은 목록) · 바이트 보존(이진 · 한글 · 깊은 경로 포함) · 범위 표시 · 로그. ### 남긴 것 (시험 도구 쪽, 제품 아님) 화면 자동 조작에서 세 번 막혔다. 모두 스크립트 문제였고 제품과 무관하다. - 함수 이름 `History` 가 PowerShell 기본 별칭(`history` = `Get-History`)과 겹쳐, 내 함수 대신 그것이 불렸다 → `GoHistory` 로 바꿈. - 폴더 창(`#32770`)은 데스크톱 바로 아래가 아니라 **본 창 아래**에 붙는다 → 본 창의 자손에서 찾게 고침. - 폴더 창의 경로 칸(`id 1152`)과 [이 폴더 선택](`id 1`)은 UIA 에서 **Pane** 으로 보이고, 같은 id 를 가진 다른 칸이 먼저 잡혔다 → id + 클래스(`Edit` · `Button`)로 고르고, 경로를 한 글자씩 친 뒤 Enter 로 닫게 함. - 백그라운드로 돌리면 앱 창이 앞으로 나오지 못해 마우스가 다른 창을 누른다 → **앞에서** 돌린다. ## A-2. 뽑은 폴더 옆에 "무엇을 뽑았는지" 안내를 남긴다 (2026-09-18, 완료) 사용자 결정(2026-09-18): 안내는 **뽑은 폴더 밖(옆)** 에 두고, 장비에서 지울 파일은 **목록으로만** 적는다(지우는 배치 파일은 만들지 않는다). ### 왜 A-1 에서 값으로 확인한 것 — 지운 파일은 "삭제되어 건너뜀 1개" 라고 개수만 알리고 **어느 파일인지 아무 데도 없었다**. 이름이 바뀐 파일은 새 이름만 뽑혀, 그 폴더를 장비에 덮어 넣으면 **옛 파일이 그대로 남는다.** 무엇과 무엇 사이를 뽑았는지도 폴더만 보고는 알 수 없었다. ### 고친 것 | 자리 | 한 일 | |---|---| | `Services/ExportReport.cs` (새 파일) | 안내 글을 만든다. 머리글(만든 때 · 만든 사람 · 저장소 · 뽑은 곳 · 범위 두 줄) · **뽑은 파일 목록**(추가 · 수정 · 이름 바뀜은 옛 이름을 괄호로) · **장비에서 지워야 할 파일 목록**(지워진 파일 · 이름 바뀐 옛 경로). `PathFor` 가 폴더 옆 이름을 정한다 — `…\변경분` → `…\변경분_변경분안내.txt`, 드라이브 뿌리처럼 옆자리가 없으면 폴더 안에 | | `Services/GitService.cs` | `ExportChangedFiles` 가 `(뽑은 수, 건너뛴 수, **무엇을 어떻게 했는지 목록**)` 을 돌려준다. git 의 상태 글자(Added · Renamed · Copied …)를 안내 글의 말로 옮기고, 이름이 바뀐 파일은 옛 경로를 함께 들고 온다 | | `Services/IGitService.cs` | 같은 서명으로 | | `ViewModels/GitViewModel.cs` | 뽑은 뒤 안내를 폴더 옆에 쓴다(`TextFile.Write`). 범위 줄은 이력에 있는 커밋이면 **제목과 날짜까지**, 시작점을 안 잡았으면 "(고른 커밋의 부모)" 를 붙인다. 안내 파일 경로를 로그에 남기고, 알림도 "지워야 할 파일 N개는 안내에" 로 바꿈. **안내를 못 써도 추출 자체는 실패로 만들지 않는다**(파일은 이미 다 뽑힌 뒤다) | | 하네스 `ReportTest` | **+14건(31 → 45)** — 머리글 · 범위 두 줄 · 요약 수 · 이름 바뀜 표기 · 지울 목록 · 지운 파일이 뽑은 목록에 없음 · 한글 경로 · 빈 목록 · 만든 사람 없음 · 폴더 옆 이름 세 가지 | ### 확인한 것 — 화면에서 뽑아 git 과 대조 | 경우 | 안내에 적힌 것 | git `diff -M --name-status` | |---|---|---| | 범위 `4eb9ece` → `cbcad8a` | 뽑은 3개(추가 `Extract/logo.bin` · **이름 바뀜** `Motion/Renamed16.cs (옛 이름 Motion/Unit16.cs)` · 추가 `한글폴더/깊은/경로/아래/설명.cs`) · **지울 2개**(옛 이름 `Motion/Unit16.cs` · 지워짐 `Recipe/Unit11.cs`) | `A logo.bin` · `R100 Unit16.cs → Renamed16.cs` · `D Unit11.cs` · `A 설명.cs` — **같음** | | 병합 커밋(시작점 없음) | 범위 `cbcad8a … (고른 커밋의 부모)` → `58d5f7f …` · 뽑은 1개 `Side/SideOnly.cs` · 지울 0개 | 같음 | - 안내 파일은 폴더 **옆**에 생긴다(`note2b_변경분안내.txt` · `note5_변경분안내.txt`). 폴더 안에는 뽑은 파일만 있다. - 알림: "3개 파일 추출 (지워야 할 파일 1개는 안내에)" · "1개 파일 추출 · 안내 note5_변경분안내.txt". Git 탭 로그에 안내 경로도 남는다. - 하네스 22벌 **1,173건** 통과(1,159 → +14) · 빌드 경고 0 · 오류 0. ### 남긴 것 (시험 도구 쪽) - 화면 잠금이 걸린 동안에는 마우스가 데스크톱에 닿지 않는다(커서 좌표가 0,0 으로 돌아가고 화면 캡처가 실패한다). 잠긴 줄 모르고 "클릭이 안 먹는다" 로 두 번 헤맸다 — 앞으로는 커서 자리와 맨 앞 창부터 본다. - 목록에서 스크롤이 필요한 줄은 **누를 때마다 자리를 다시 읽어야** 한다. 옛 자리로 누르면 조용히 빗나가고, 그 뒤 [여기부터] 가 엉뚱한 커밋(HEAD)으로 잡혀 범위가 거꾸로 됐다. - PowerShell 변수는 대소문자를 안 가린다 — `$S`(경로)와 `$s`(파일 글)가 겹쳐 경로가 깨졌다(9차 A-2 와 같은 종류). ## A-3. 이미 파일이 있는 폴더 · 쓰다 막힐 때 (2026-09-18, 완료) 사용자 결정(2026-09-18): **고른 폴더 아래 새 폴더를 만든다** · 쓰다 막히면 **먼저 보고 시작한다**(하나라도 못 쓰면 아무것도 쓰지 않는다). ### 고친 것 | 자리 | 한 일 | |---|---| | `Services/ExportPlan.cs` (새 파일) | `FolderName` — `변경분_4eb9ece..cbcad8a_2026-09-18` 처럼 범위와 날짜가 들어간 이름. `UniquePath` — 같은 이름이 있으면 `_2` · `_3`. `Blocked` — 쓰기 전에 읽기 전용 · 다른 프로그램이 잡고 있는 파일을 걸러 목록으로. `BlockedMessage` — 사람에게 보일 글(앞 다섯 개 + "외 N개") | | `Services/GitService.cs` | 뽑기 전에 `ExportPlan.Blocked` 로 **먼저 본다**. 하나라도 막히면 폴더도 만들지 않고 `IOException` 으로 멈춘다 — 예전에는 앞 순서만 써진 반쯤 뽑힌 폴더가 남았다(A-1 경우 9) | | `ViewModels/GitViewModel.cs` | 고른 폴더에 바로 쏟지 않고 **그 아래 새 폴더**를 만들어 거기에 뽑는다. 안내 글은 그 폴더 옆(= 고른 폴더 안)에 붙는다. 알림도 폴더 이름을 앞에 — "변경분_4eb9ece..cbcad8a_2026-09-18 에 3개 (지워야 할 파일 1개는 안내에)" | | 하네스 `ReportTest` | **+12건(45 → 57)** — 폴더 이름 · `_2` · `_3` · 읽기 전용은 막힘 · 아직 없는 파일은 막힘 아님 · 열려 있는 파일은 막힘 · 보일 글의 개수와 줄임 | ### 확인한 것 — 화면에서 이미 파일이 있는 폴더(사람이 넣어 둔 `사용자메모.txt` · 옛 폴더 `옛자료`)를 골라 같은 범위를 **두 번** 뽑았다. | 때 | 결과 | |---|---| | 첫 번째 | `…\a3\변경분_4eb9ece..cbcad8a_2026-09-18` 에 3개 · 안내는 그 옆에 | | 두 번째 | `…_2` 폴더가 새로 생기고 거기에 3개 · 안내도 `…_2_변경분안내.txt` | | 고른 폴더 안 | 새 폴더 둘 · 안내 둘 · **사용자메모.txt 와 옛자료 그대로** — 섞이지 않았다 | - **먼저 보기**(`Blocked`)는 하네스 12건으로 확인했다. 화면에서는 재현되지 않는데, 뽑을 때마다 **비어 있는 새 폴더**를 만들기 때문이다 — A-1 경우 9(반쯤 뽑힌 폴더)가 애초에 생기지 않는다. 남겨 둔 까닭은 폴더가 이미 있는 드문 경우(다른 프로그램이 같은 이름을 방금 만든 경우)와, 나중에 폴더를 다시 쓰게 고칠 때를 위한 것이다. - 하네스 22벌 **1,185건** 통과(1,173 → +12) · 빌드 경고 0 · 오류 0. ### 남은 것 - A-4(ZIP)는 아직 정하지 않았다. - 매뉴얼 · 웹 문서의 변경분 추출 설명(새 폴더 · 안내 파일)은 E-2 에서 함께 고친다. ## B-1. 배포 묶음을 다시 만들고 꼭 필요한 파일을 가림 (2026-09-22, 완료) ### 고치기 전 — 매뉴얼이 가리키는 Release 는 09-07 것 | 무엇 | 값 | |---|---| | `bin\Release\net48` | 65개 · 96MB. `MergeHub.dll` 09-07 14:11, 셸 09-07 13:41 (플랫폼은 그 뒤 09-16 에 다시 배포됨) | | 옛 Release 로 켜면 | 오류 없이 켜지지만 **본 탭이 3개**(지금은 4개 — 폴더 비교 탭이 없음). 지금 소스의 형식 142개 가운데 **74개가 옛 dll 에 없다** — 폴더 비교(`FolderView` · `FolderComparer`), 3분할(`ThreeWayAligner`), 병합 저장 판단(`MergeSavePlan`), 단축키(`ShortcutMap`), 변경분 안내(`ExportReport` · `ExportPlan`), 커밋 수정 판단(`CommitSelection` · `CommitReword`) 등 6차 이후 것 (`e11-b1-old.ps1`, 이름 대조) | ### 무엇이 필요한지 가린 길 1. **참조로** — 셸 · MergeHub 에서 시작해 dll 이 부르는 dll 을 따라갔다. 어디서도 닿지 않는 것 7개: `GLWpfControl` · `OpenTK` · `SkiaSharp.Views.WPF` · `SkiaSharp.Views.Desktop.Common` · `LiveChartsCore.SkiaSharpView.WPF` · `Microsoft.Extensions.Options` · `…Options.ConfigurationExtensions`. 플랫폼 dll 안에 이 이름이 글자로도 없다(XAML 로 부르는 것도 아님). 2. **플랫폼이 쓰는 것** — `UbisamBase.Core` 가 `SkiaSharp` · `LiveChartsCore` · `LiveChartsCore.SkiaSharpView` 를 **직접 참조**한다(`Charting/ChartTheme.cs`, 테마를 바꿀 때 `UiSettingsService` 가 부름). MergeHub 는 안 쓰지만 **플랫폼 몫이라 남긴다**(사용자 결정 2026-09-22 — 빼면 약 8MB 가 되지만 플랫폼이 바뀔 때마다 다시 재야 한다). 3. **셸이 켜질 때 하는 일** — 셸은 폴더의 `*.dll` 을 모두 `Assembly.LoadFrom` 으로 열어 `IAppSetup` 을 찾는다(`AppSetupLoader.cs:16`). 쓰지 않는 dll 도 이름 순서상 `MergeHub.dll` 앞이면 켤 때마다 읽힌다 — 빼면 그만큼 덜 읽는다. `Lang` 폴더는 없으면 플랫폼이 만든다(`LanguageService.cs`), 지금은 비어 있다. 4. **다른 OS · CPU** — 맥용 dylib 3개(17.5MB), 리눅스 · 맥용 libgit2 9개(약 19MB), ARM 용(Skia · HarfBuzz 11MB, libgit2). 이 PC 에서 셸은 **64비트**로 뜬다. x86 은 32비트 Windows 를 위해 남긴다. 5. **지워 보고 켜서** — 통째 복사본(65개 · 97MB)과 줄인 묶음(41개 · 44MB)을 `%TEMP%` 에 따로 두고 켰다. 둘 다 오류 없이 켜지고 본 탭 4개가 모두 열렸다(UIA 로만 이동, `e11-b1-run.ps1`). ### 빈 폴더에서 병합 한 길 (`e11-b1-merge.ps1` — 10차 E-1 의 병합 길 그대로, 실행 파일만 묶음으로) | 무엇 | 결과 | |---|---| | 실행 파일 | `%TEMP%\mergehub-beta\UbisamBase.Shell.exe` (줄인 묶음) | | 병합 | `feature/theirs → feature/mine` 충돌 24건 (머지 주석만 다른 2건 자동) | | 풀기 | 파일 단위 15 · 줄 단위 7 · 파일 지우기 · 남기기 · 누른 Take 18번 = 줄 고른 로그 18줄 | | 병합 커밋 | `647f1f8` 부모 둘 · 본문 "충돌 해결 26개" · 줄끝 · BOM · 인코딩 바뀐 파일 0 · 충돌 표식 0 · 워킹트리 깨끗 | | 두 탭 | Git 탭에서 고른 커밋을 파일 비교 탭이 따라감(10차 B-1) | | 걸린 시간 | 304초 | ### 만든 것 | 자리 | 한 일 | |---|---| | `scripts\make-bundle.ps1` (새) | Release 빌드(vswhere 로 MSBuild 를 찾음, `-NoBuild` 로 건너뜀) → 뺄 것 24개를 **까닭과 함께 한 표**에서 빼고 → `-Out`(기본 `%TEMP%\mergehub-beta`)에 옮기고 → 꼭 있어야 할 것(셸 · Core · MergeHub · LibGit2Sharp · git2 x64)을 확인하고 → 묶음 안에 `배포묶음.txt`(파일 · 크기 · 까닭, 뺀 것 · 까닭, 만든 시각 · 커밋)를 쓴다. **다른 파일이 든 폴더는 비우지 않고 멈춘다**(`배포묶음.txt` 가 있는 폴더 · 빈 폴더만) — 남의 파일을 넣어 둔 폴더로 확인함 | | 매뉴얼(`doc/web/index.html` 켜기와 탭 구성) | "Release 로 다시 빌드해야 최신" · 다른 PC 에는 스크립트로 묶음을 만들어 폴더째 복사 · `배포묶음.txt` 설명 | - 스크립트로 만든 묶음이 손으로 만들어 시험한 묶음과 **파일 목록이 같고**, 다시 켜도 오류 없이 네 탭이 열렸다. - Release 빌드 경고 0 · 오류 0. 제품 코드 변경 없음(스크립트 · 문서만). ### 배포 묶음 (41개 · 43.5MB) | 묶음 | 파일 | 크기 | 까닭 | |---|---|---|---| | 셸 · 플랫폼 | `UbisamBase.Shell.exe` · `.exe.config` · `UbisamBase.Core.dll` | 0.7MB | 켜는 것 · .NET 4.8 · 버전 맞춤 · 플랫폼 | | MergeHub | `MergeHub.dll` | 0.6MB | 셸이 폴더의 dll 을 훑어 찾는다 | | Git | `LibGit2Sharp.dll` · `lib\win32\x64\git2-*.dll` · `lib\win32\x86\git2-*.dll` | 4.0MB | Git 조작 · 네이티브 | | MVVM · 인코딩 | `CommunityToolkit.Mvvm.dll` · `System.Text.Encoding.CodePages.dll` | 0.8MB | 플랫폼 · MergeHub · CP949 판별 | | 플랫폼 설정 · DI | `Microsoft.Extensions.*` 11개 | 0.5MB | 플랫폼 | | .NET 보강 | `System.*` 9개 · `Microsoft.Bcl.AsyncInterfaces` | 1.1MB | 플랫폼 · Json | | 차트(플랫폼 몫) | `LiveChartsCore` 둘 · `SkiaSharp` 둘 · `HarfBuzzSharp` · 네이티브 6개(루트 · x64 · x86) | 35.8MB | 플랫폼 Core 가 참조(`ChartTheme`) | ### 남은 것 - 묶음은 `%TEMP%` 에 있다. 다른 PC 에 줄 자리(공유 폴더 · 문서 폴더)는 베타 때 정한다. - 지시서의 "다섯 탭" 은 지금 본 탭 4개(폴더 비교 · 파일 비교 · Git · 설정)다 — 지시서 글이 옛 것. - 웹 문서 발행(아티팩트)은 E-2 에서. - 플랫폼 배포 폴더(`D:\UbisamPlatform\bin`)는 **손대지 않았다**. 플랫폼 README 가 "UbisamBase.Shell 을 Release 로 빌드하면 이 폴더를 갱신" 한다고 하므로, 플랫폼을 새로 배포하면 이 스크립트를 다시 돌려야 한다. ## B-2. D 드라이브가 없는 PC · 설정이 없는 첫 실행 (2026-09-22, 완료 — 플랫폼에서 고치고 확인 뒤 배포) 지시서대로 **D 드라이브는 건드리지 않았다.** `D:\UbisamConfig` 는 먼저 통째로 백업하고(20개, 파일마다 SHA256 · 크기 · 수정 시각 목록) 이름만 잠시 바꿔 재고, 끝날 때마다 되돌려 목록과 대조했다(두 번 모두 같음). 시험은 모두 UIA 로만 누르고 읽었다(마우스 · 키보드 · 화면 찍기 없음). ### 설정이 없는 첫 실행 (배포 묶음 `%TEMP%\mergehub-beta`, `e11-b2.ps1`) | 볼 것 | 결과 | |---|---| | 오류 창 | **없음** | | 이름 창 | 빈 칸으로 뜬다 · 빈 채로 [저장] 하면 "이름을 입력하세요." 로 막힘 · 이름을 넣고 [저장] 하면 닫힘 | | 켜는 순간 생기는 것 | `Settings\MergeHubSettings.json` · `Settings\UiSettingsService.json`. 이름을 저장하면 `CurrentUserService.json`, 첫 기록 때 `Log\` | | 기본값 | `MergeHubSettings.json` 이 매뉴얼 설정 표와 **모두 같다** — 원격 이름 origin · 줄 필터 켬 · 단어 단위 · 문법 강조 켬 · 커밋 조회 200 · 머지 주석 남기기 · 무시 켬 · C# 스타일 1(AURORA, F-12) · 공백 단계 0 · 나머지 비움 | | 창 위치 | 주 모니터에 **최대화**(2560×1600). 닫으면 `ShellWindowPlacement.json`(보통 크기 2048×1222 · Maximized true) | | 네 탭 | 모두 열림, 오류 글 없음 | ### D 드라이브가 없을 때 — 코드로 따라가고, 같은 줄에서 실패하게 해 봄 - 셸 `App.OnStartup` → `UbisamAppBuilder.Run` 의 첫 줄 `UiSettingsService.Initialize(D:\UbisamConfig)` → `Directory.CreateDirectory(D:\UbisamConfig\Settings)`(`UiSettingsService.cs:86`)에 **감싼 곳이 없다**. 드라이브가 없으면 `DirectoryNotFoundException`. 로그 서비스는 그보다 **뒤에** 준비된다. - 드라이브를 없애는 대신 `D:\UbisamConfig` 자리에 **같은 이름의 빈 파일**을 두면 같은 줄이 `IOException` 으로 실패한다. - 결과: 셸의 공용 예외 창 **"문제가 생겼습니다 — 작업 중 문제가 생겨 이 동작을 멈췄습니다. 프로그램은 계속 쓸 수 있습니다 … 자세한 내용은 D:\UbisamConfig\Log 아래 로그 파일에 남았습니다."** 두 말 모두 사실이 아니다(본 창 없음 · 로그 없음). [확인] 을 누르면 **창 없는 프로세스가 30초 뒤에도 남았다**. 다시 켜면 하나씩 더 쌓인다. ### 정한 것 (2026-09-22 사용자) · 고친 것 — 플랫폼 - **D 를 못 쓰면 `%LOCALAPPDATA%\UbisamConfig`** 에 쓴다(권장안). **켜는 중 실패는 알리고 끝낸다**(권장안). - 플랫폼 커밋 `377ffd3` — `Bootstrap/ConfigLocation`(새) · `Bootstrap/StartupMessages`(새) · `UbisamAppBuilder.ConfigRoot` 를 `const` → 속성(+ `ConfigFallbackReason`), 로그를 가장 먼저 준비 · `LockConfirmDialog` 의 ScreenSaver 자리 · `LogService.LogDirectory` · 셸 `App.OnStartup` 에서 켜는 중 실패를 받아 `Shutdown(1)`. 플랫폼 `changelog.md` 에 다른 소비 프로그램 영향과 함께 적음, `platform-guide.md` 11장 · 세 곳 고침. - 하네스 `PlatformCfgTest`(새, 플랫폼 두 파일을 엮음) **24건** — 자리 고르기 · 둘 다 안 될 때 · 실제 임시 폴더 · 같은 이름 파일 · **없는 드라이브 글자**로 실제로 다른 자리를 고름 · 실패 글(켜는 중에는 "계속 쓸 수 있습니다" 를 안 함 · 로그가 없으면 "남았습니다" 를 안 함). - 플랫폼은 **Debug 로만** 빌드했다(경고 0 · 오류 0). Release 는 빌드 후 단계가 곧바로 `D:\UbisamPlatform\bin` 을 덮어쓰기 때문이다 — 배포 폴더는 그대로(09-16). ### 고친 뒤 (배포 묶음에 고친 Debug Core · Shell 두 파일만 바꿔 넣은 `%TEMP%\mergehub-beta-b2`) | 경우 | 결과 | |---|---| | D:\ 에 만들 수 있을 때 | 예전처럼 `D:\UbisamConfig` · `%LOCALAPPDATA%` 에 아무것도 안 생김 · 경고 없음 | | D:\ 자리가 막혔을 때 | `C:\Users\Ubisam\AppData\Local\UbisamConfig` 에 Settings 넷 · Log 가 생기고 이름 창 → 네 탭 → 정상 종료. 로그 첫 줄 `[W] Platform: D:\UbisamConfig 를 쓸 수 없어 C:\Users\Ubisam\AppData\Local\UbisamConfig 에 설정 · 로그를 둡니다 (같은 이름을 가진 파일 또는 디렉터리가 이미 있어서 …)` | | 두 자리 모두 막혔을 때 | 창 **"켜지 못했습니다"** — "프로그램을 켜지 못해 끝냅니다. 설정 폴더를 만들 수 없습니다. D:\UbisamConfig : … / C:\Users\Ubisam\AppData\Local\UbisamConfig : …" (로그가 없으니 로그 얘기는 없음) → [확인] 뒤 **프로세스 끝남** | - MergeHub 는 이전 Core 로 빌드된 그대로 새 Core 위에서 돌았다(바뀐 것은 속성 추가뿐, MergeHub 는 `ConfigRoot` 를 읽지 않는다). - MergeHub 쪽: 매뉴얼 "설정 — … MergeHubSettings.json 에 저장된다" 에 D 없는 PC 의 자리를 덧붙이고, `MergeHubSettings.cs` 주석을 사실대로. 하네스 22벌 1,247건 그대로 · 빌드 경고 0 · 오류 0. ### 배포 (2026-09-22 사용자 확인 뒤) - `publish-platform.ps1` 로 `D:\UbisamPlatform\bin` 갱신(배포 시각 11:27:25, 경고 0 · 오류 0). 48개 가운데 바뀐 것은 **`UbisamBase.Core.dll` · `UbisamBase.Shell.exe` · `README.txt` 셋**, 없어진 파일 없음(배포 전 목록 · 해시와 대조). - MergeHub 를 다시 빌드하고 `make-bundle.ps1` 로 묶음을 다시 만듦(41개 · 43.5MB). 묶음 · Debug 출력의 Core · Shell 이 배포 폴더와 해시가 같다. 새 묶음으로 켜 네 탭 오류 없음 · 로그에 자리 경고 없음(D 를 씀). - 시험이 남긴 것(시험용 설정 폴더 셋 · 빈 파일 셋 · `%LOCALAPPDATA%` 쪽 폴더 · 시험 묶음 둘)은 사용자 말대로 모두 지움. `D:\UbisamConfig` 원본만 남음. ### 남은 것 - 드라이브는 있는데 **읽기 전용**(CD · 쓰기 막힌 USB)인 경우도 같은 길(`CreateDirectory` 실패 → 다른 자리)로 가지만 재 보지는 않았다. 폴더는 있는데 파일만 못 쓰는 경우(권한)는 이번에 다루지 않았다. ## C-1. 있는 [커밋 수정] 을 다시 내 보고 바로잡음 (2026-09-18, 완료 — 8 만 이번 범위 밖) ### 고치기 전에 여덟 가지를 화면에서 다시 냈다 시험 저장소: `C1Repo` 위에 `amend` 브랜치를 만들고 **작성자 박지훈인 커밋**을 HEAD 로, 다른 브랜치(`feature/revert`)에는 **더 새 커밋**을, 그리고 bare 저장소를 원격으로 걸어 upstream 을 두었다(`e11-c1-setup.sh`). | # | 고치기 전에 본 것 | |---|---| | 1 | [모든 브랜치] 켠 채 [마지막 메시지] → 칸에 `딴 브랜치 최신 작업`(HEAD 아님). 그대로 [커밋 수정] 하니 **HEAD 제목이 그 메시지로 바뀌었다** | | 2 | 앱에서 [전체 스테이징] 한 파일이 **말없이 커밋에 들어갔다**(남은 변경 없음). 알림은 "커밋 수정" 뿐 | | 3 | 작성자 `박지훈` · 작성 `2026-09-15 10:00` → **`시험` · `2026-09-18 15:48`** 로 바뀜 | | 4 | 충돌 24개가 남은 채로도 단추가 **켜져 있고**, 누르면 `[커밋 수정] 실패: cannot create a tree from a not fully merged index` | | 5 | 병합 커밋을 고쳐도 **부모 둘 · 본문(충돌 해결 26개 · 29줄) 그대로** | | 6 | 원격에 이미 올라간 커밋도 **막지 않고** 고쳐졌고, 그 뒤 [Push] 가 `cannot push non-fastforwardable reference` 로 거부됨 | | 7 | 알림 · 로그에 **새 해시만**(`커밋: 61653f5 …`). 고치기 전 해시는 어디에도 없음 | | 8 | 커밋 메시지 칸이 한 줄짜리라 **여러 줄 메시지를 아예 칠 수 없다**. `#` 로 시작하는 글자는 그대로 들어간다 | ### 고친 것 (1 · 3 · 4 · 7) | 자리 | 한 일 | |---|---| | `Services/CommitSelection.cs` | `MessageOfHead` — [마지막 메시지] 는 **HEAD 커밋**의 메시지를 읽는다(목록 순서와 무관). HEAD 가 목록에 없으면 아무것도 주지 않는다. `CanAmend` — **작업 중이면 끈다**. `AmendHint` — 꺼진 까닭을 단추 설명으로. `AmendDone` — "커밋 수정 완료 (옛 abc1234 → 새 def5678) · 파일 N개 포함" | | `Services/GitService.cs` | 고쳐 쓸 때 **원래 작성자 · 작성 시각을 그대로** 쓴다(git 과 같게). 커밋한 사람 · 시각만 지금 | | `Services/GitWorkspace.cs` | `HeadFullSha` 를 들고 있는다 — 이력 목록의 Sha 와 맞춰 보려면 짧은 해시로는 모자란다 | | `ViewModels/GitViewModel.cs` | 위 판단을 붙이고, 고치기 전 해시 · 함께 들어간 파일 수를 알림에. 작업이 시작 · 끝날 때 단추 설명도 다시 그린다 | | `Views/GitView.xaml` | [커밋 수정] 설명을 상황에 따라 바뀌는 값으로 | | 하네스 `MergeSaveTest` | **+15건(210 → 225)** — HEAD 메시지 읽기(맨 위가 딴 브랜치여도 · 대소문자 · HEAD 가 목록에 없음 · 빈 목록) · 켜는 조건 넷 · 꺼진 까닭 · 알림 글 셋 | ### 고친 뒤 같은 순서로 다시 | # | 결과 | |---|---| | 1 | 칸에 **`남이 만든 커밋`**(HEAD 것) | | 3 | 고친 뒤에도 작성자 `박지훈` · 작성 `2026-09-15 10:00` **그대로**, 커밋한 사람 · 시각만 지금 | | 4 | 충돌 24개가 남은 동안 단추 **꺼짐** — 누를 수 없고, 누른 뒤 실패 알림도 없다 | | 7 | 알림 **`커밋 수정 완료 (옛 bcd2c43 → 새 fd7810c) · 파일 1개 포함`** | - 하네스 22벌 **1,200건** 통과(1,185 → +15) · 빌드 경고 0 · 오류 0. ### 이어서 고친 것 (2 · 6) — "먼저 묻기" (2026-09-18 사용자 결정) 두 가지 모두 **막지 않고 먼저 묻는다**. 막으면 정말로 그러려는 사람(빠뜨린 파일을 같이 넣기 · 아직 남이 안 받은 커밋 고치기)까지 못 하게 되고, 그대로 두면 모르는 새 벌어진다. | 자리 | 한 일 | |---|---| | `Services/CommitSelection.cs` | `AmendWarning(스테이징 수, 이미 올림, 원격 브랜치)` — 물을 것이 없으면 **null**(안 묻는다). 있으면 해당하는 줄만 모아 "… ¶ 계속할까요?" 한 글로 | | `ViewModels/GitViewModel.cs` | `StagedFileCount`(충돌 뺀 스테이징 수) · `HeadTrackedBranch` · `IsHeadAlreadyPushed`(추적 브랜치가 있고 앞선 커밋 0개). 물을 것이 있으면 `MessageUtil.ShowYesNo` 로 먼저 묻고, [아니오] 면 **커밋도 메시지 칸도 그대로 두고 아무 일도 하지 않는다** | | 하네스 `MergeSaveTest` | **+7건(225 → 232)** — 안 묻는 경우 · 스테이징만 · 올린 것만 · 둘 다 · 브랜치 이름을 모를 때 "원격" · "Push 가 거부됩니다" · 끝이 늘 "계속할까요?" | 앞선 커밋 수는 **마지막 fetch 시점** 기준이라, fetch 전에 남이 받아 간 것까지는 알 수 없다. 그래서 막지 않고 묻기만 한다(주석에 남김). ### 고친 뒤 화면에서 (`e11-c1g.ps1`) 스테이징 1개를 만들어 두고, HEAD 가 `origin/amend` 와 같은 자리인 채로 냈다 — **두 가지가 겹치는 자리**다. | 무엇 | 결과 | |---|---| | [커밋 수정] 누름 | 확인 창 `커밋 수정` — "스테이징해 둔 파일 1개도 이 커밋에 들어갑니다. / 이 커밋은 origin/amend 에 이미 올라가 있습니다. 고치면 다음 Push 가 거부됩니다. / 계속할까요?" · 단추 [아니오] [예] (`e11-c1g-ask.png`) | | [아니오] | HEAD `62dd57f` **그대로** · 스테이징 `Recipe/Unit19.cs` **그대로** · 메시지 칸 `묻는지 확인` **그대로** · 창 닫힘 | | 다시 누르고 [예] | HEAD `62dd57f` → `6207b26` · 알림 `커밋 수정 완료 (옛 62dd57f → 새 6207b26) · 파일 1개 포함` | | 스테이징 없음 · 원격보다 앞선 자리에서 다시 | **안 묻고 바로** 고침 (`ceaab5f`, 작성자 `박지훈` 그대로) (`e11-c1g-done.png`) | - 하네스 22벌 **1,207건** 통과(1,200 → +7) · 빌드 경고 0 · 오류 0 · 설정 파일 해시 같음. ### 남은 것 - **8. 여러 줄 커밋 메시지** — 칸이 한 줄이라 본문을 칠 수 없다. 이번 범위 밖으로 적어 둔다(병합 커밋 본문은 앱이 저절로 붙인다). C-2 의 [메시지 바꾸기] 창은 여러 줄을 받는다. - C-2 는 아래(2026-09-22 완료). ## C-2. 마지막이 아닌 커밋의 메시지 바꾸기 (2026-09-18 ~ 09-22, 완료 — 좁은 범위) 사용자 결정(2026-09-18): **한다 — 좁은 범위로.** 화면은 기획안 문구대로 **이력 줄 우클릭 메뉴**. ### 고치기 전 - 이력 줄을 우클릭해도 **메뉴가 없고**, 이력 탭 단추는 Revert · Cherry-pick · Reset · 여기부터 · 해제 · 변경분 추출뿐이었다(`e11-c2-before.ps1`). 고른 커밋의 메시지를 바꿀 길이 없었다. - 메시지는 커밋 해시에 들어가므로, HEAD 가 아닌 커밋을 바꾸면 **그 커밋부터 HEAD 까지가 새 해시로 다시 써진다**. 아직 안 올린 커밋이면 브랜치가 새 줄기로 옮겨 갈 뿐이지만, 올린 뒤라면 남의 이력과 갈라진다(사용자에게 설명함). ### 만든 것 | 자리 | 한 일 | |---|---| | `Services/CommitReword.cs` (새) | 막을 까닭 — 고른 커밋 없음 · 작업 중 · 커밋 안 한 변경 · 지금 브랜치 조상 아님 · 원격에 올라감 · 다른 로컬 브랜치도 품음 · 구간에 태그 · 사이에 병합 커밋. 먼저 풀어야 할 것부터 말하고 **푸는 길**까지 적는다. 확인 글 · 완료 알림 · 메뉴 설명. `Clean` — 새 메시지를 git `-m` 처럼 다듬는다(아래) | | `Services/GitService.cs` · `IGitService.cs` · `Models/GitModels.cs` | `InspectReword` — 저장소에서 사실만 읽는다(다시 쓸 수 · 병합 수 · 올라간 원격 브랜치 · 다른 브랜치 · 태그). `RewordCommit` — LibGit2Sharp `Refs.RewriteHistory` 로 **고른 커밋의 메시지만** 갈고 트리 · 작성자 · 작성 시각 · 부모 관계는 그대로. 바꾸기 전 자리는 `refs/original/날짜-시각/` 에 남긴다(같은 자리에 두 번 쓰면 libgit2 가 막아서 시각을 붙임). 고친 커밋의 새 해시도 돌려준다 | | `Views/RewordWindow.xaml(.cs)` (새 창) | 새 메시지를 받는 창. 고친 커밋 한 줄(해시 · 작성자 · 날짜) · 몇 개가 다시 써지는지를 늘 보이고, **여러 줄**을 받는다. 지금 메시지를 미리 넣어 전체를 골라 둔다. [바꾸기] 는 기본 단추가 아니다(Enter 는 줄바꿈) | | `Views/GitView.xaml(.cs)` | 이력 목록의 우클릭 메뉴 **[메시지 바꾸기...]** — MergeHub 의 첫 우클릭 메뉴. 목록은 오른쪽 누름으로 선택이 안 바뀌므로 **우클릭한 줄을 먼저 고른다**(10차 B-1 처럼 저장 안 한 편집이 있으면 먼저 묻고 [취소] 면 메뉴도 안 연다) | | `ViewModels/GitViewModel.cs` | 막힐 자리면 메뉴를 끄지 않고 **눌렀을 때 까닭을 알림으로** — 까닭은 저장소를 읽어 봐야 알고, 꺼 두면 왜 안 되는지 알 길이 없다. 되면 창 → 확인 창 → 실행 → 고른 커밋이 **새 해시**를 따라간다 | | 하네스 `MergeSaveTest` | **+40건(232 → 272)** — 막는 여덟 가지와 보는 순서 · 확인 글 · 완료 알림 · 빈 메시지 · 안 바뀐 메시지 · 다듬기 아홉 | ### 화면에서 찾아 고친 것 — 끝 줄바꿈 첫 회차에 새 메시지가 **줄바꿈 없이** 저장됐다(`셋` 으로 끝남). git 이 만든 커밋은 늘 `\n` 으로 끝나고, MergeHub 의 [커밋] · [커밋 수정]도 libgit2 가 다듬는다. 칸을 어떻게 고쳤느냐에 따라 끝 줄바꿈이 있다 없다 했다. libgit2 의 다듬기(`PrettifyMessages`)를 켜면 **손대지 않은 뒤 커밋들 메시지까지** 다듬어지므로, 새 메시지 하나만 `CommitReword.Clean` 으로 다듬는다(줄 끝 공백 · 앞뒤 빈 줄 없앰, 빈 줄 여럿은 하나, 끝은 줄바꿈 하나, `#` 줄 · 들여쓰기는 둠). 검사 9건을 먼저 넣어 실패를 보고 고쳤다. 같은 회차의 다른 둘은 **스크립트 탓**으로 가렸다(`e11-c2-probe.ps1`): 첫 우클릭이 안 먹은 것은 창을 앞으로 부르는 도우미가 다른 프로그램 창을 앞으로 가져와 클릭이 앱에 안 닿은 것, 한글이 한 글자만 들어간 것은 8ms 간격으로 몰아 친 것. 150ms 간격으로 치면 그대로 들어갔다. ### 고친 뒤 화면에서 (`e11-c2-setup.sh` · `e11-c2a.ps1` · `e11-c2b.ps1` · `e11-c2c.ps1`) 시험 저장소: `reword` 브랜치에 커밋 넷(작성자 박지훈 · 이수진, 셋째는 일부러 **"셋제 커밋"** 오타). 막힐 자리로 `pushed`(bare 원격에 올림) · `merged`(사이에 병합) · `shared` + `shared-copy` · `tagged`(v9.9). **되는 자리** — "셋제 커밋" 우클릭 → [메시지 바꾸기...] | 무엇 | 결과 | |---|---| | 우클릭 | 그 줄이 먼저 골라지고 메뉴 `메시지 바꾸기...` | | 창 | `83ed0b2 · 박지훈 · 2026-09-16 11:00` · "이 커밋과 그 뒤 1개, 모두 2개가 새 해시로 다시 써집니다" · 칸에 `셋제 커밋` (`e11-c2-window.png`) | | [취소] | HEAD `4c0263e` 그대로 | | "셋째 커밋" 치고 [바꾸기] | 확인 창 "83ed0b2 "셋제 커밋" 의 메시지를 바꿉니다. 이 커밋과 그 뒤 1개, 모두 2개가 새 해시로 다시 써집니다. 내용 · 작성자 · 작성 시각은 그대로입니다. 바꾸기 전 HEAD 4c0263e 는 로그에 남겨…" (`e11-c2-confirm.png`) | | [예] | 알림 `메시지 바꿈 완료 (옛 HEAD 4c0263e → 새 HEAD 1b11c03) · 커밋 2개 다시 씀` · 로그 `… · 되돌릴 자리 refs/original/20260922-102604/` | | git 대조 | 넷째 · 셋째: **트리 해시 · 작성자 · 작성 시각 같음**, 해시만 새것. 제목은 셋째만 바뀜. 둘째 아래는 해시까지 그대로 · 커밋 수 같음 · 워킹트리 깨끗 | | 메시지 끝 | `셋째 커밋\n` — 손 안 댄 넷째(`넷째 커밋\n`)와 같은 꼴 | | 고른 커밋 | 새 해시 `b2d9880` 을 따라감 | | 되돌리기 | `git reset --hard refs/original/20260922-102604/heads/reword` → `4c0263e … 셋제 커밋` 이 그대로 돌아옴 | **막히는 자리** — 모두 창이 안 뜨고 HEAD 그대로, 알림에 까닭 | 자리 | 알림 | |---|---| | 올린 커밋 | "이 커밋은 origin2/pushed 에 이미 올라가 있습니다. 올린 커밋을 다시 쓰면 남의 이력과 갈라져 막습니다." | | 사이에 병합 | "고른 커밋과 HEAD 사이에 병합 커밋이 1개 있습니다. 병합 이력은 다시 쓰지 않습니다." | | 다른 브랜치도 품음 | "이 커밋을 다른 브랜치도 품고 있습니다(shared-copy). 그 브랜치까지 다시 써야 해서 막습니다." | | 구간에 태그 | "다시 쓸 구간에 태그가 있습니다(v9.9). 태그가 가리키는 커밋이 사라져 막습니다." | | 작업 중(병합 충돌 26개) | "병합 · rebase · cherry-pick · revert 를 끝낸 뒤에 쓸 수 있습니다." | | 커밋 안 한 변경 | "커밋하지 않은 변경이 있습니다. 먼저 커밋하거나 stash 한 뒤에 바꾸세요." | | 다른 브랜치에만([모든 브랜치]) | "지금 브랜치에서 닿지 않는 커밋입니다. 그 커밋이 있는 브랜치로 체크아웃한 뒤에 바꾸세요." (`e11-c2-other.png`) | | 파일 비교 탭에 저장 안 한 편집 | 우클릭하자 `저장하지 않은 편집` 창("Common/Util/Unit103.cs 에 저장하지 않은 편집이 있습니다. 다른 커밋을 봅니다.") → [취소] 면 메뉴도 안 열리고 선택 그대로 (`e11-c2-unsaved.png`) | - 하네스 22벌 **1,247건** 통과(1,207 → +40) · 빌드 경고 0 · 오류 0 · 설정 파일 해시 같음. ### 알아 둘 것 - 판단은 **마지막 fetch 시점** 기준이다. fetch 전에 남이 올린 것까지는 모른다(C-1 과 같음). - 되돌릴 자리 `refs/original/…` 은 이력 목록에 안 보인다(목록은 브랜치만 훑음). 지우는 단추는 두지 않았다 — 되돌릴 일이 없으면 그대로 두어도 된다. - HEAD 커밋도 이 메뉴로 바꿀 수 있다. [커밋 수정] 과 달리 **스테이징한 파일이 들어가지 않는** 메시지만 고치는 길이다. ## D-1. 시험 도구 둘 (2026-09-22, 완료 — 제품 코드 변경 없음) | 도구 | 고치기 전 | 고친 것 | |---|---|---| | `d1-verify.ps1` (줄끝 · BOM · 표식 검사) | 부모 하나인 커밋(rebase · cherry-pick · revert)에도 없는 둘째 부모로 `git merge-base` 를 불러 사용법 글 · `null` 오류를 찍었다(판정 숫자는 맞았음) | 부모가 하나면 **첫 부모와만 견준다고 적고** merge-base 를 부르지 않는다. 견줄 부모 쪽 파일이 없는 새 파일은 가운데 BOM · 줄끝 섞임만 본다 | | `d7lib.ps1` 의 `FileState` (파일 비교 탭 요약 읽기) | 요약 글을 "남은 충돌 · 충돌 정리 끝 · 남은 차이" 로만 찾아, 제품이 쓰는 **"차이 없음"**(편집이 있으면 "차이 없음 · 편집 N건 …")을 못 읽고 커밋 뒤 요약을 빈칸으로 적었다 | "차이 없음*" 도 요약으로 읽는다 (`HomeViewModel.cs:3486` 의 글과 맞춤) | 확인: - 앱 없이 — 시험 저장소 HEAD(revert 커밋 `d59bc42`, 부모 하나)에 돌려 **오류 · 사용법 줄 0**, 결과는 E-1 revert 때와 같음(36개 · 다른 파일 0). - 판정대로 rebase 한 길을 다시(`e11-e1-merge.ps1 -Way rebase`, 298초) — **오류 줄 0**, `[계속]` 뒤 파일 비교 탭 요약 **"차이 없음"**, "부모: … 하나 — 첫 부모와만 견준다", 누른 Take 18 = 로그 18 · 줄끝 · BOM 0/31 · 표식 0 · class 0 · 워킹트리 Clean · 설정 해시 같음. - 고치기 전 두 파일은 `*.d1bak` 로 남김(시험 도구 폴더, 저장소 밖). ## E-1. 바꾼 길을 다시 끝까지 (2026-09-22, 완료 — 새로 걸린 것 없음) 11차에서 바뀐 것에 맞춰 넷을 돌렸다. A(변경분 추출) · C-1 · C-2 를 고쳤고, F-12 가 비교 · 저장에 걸리는 C# 스타일 기본값을, B-2 가 플랫폼 시작부를 바꿨으므로 **다섯 길 + pull** 도 다시 했다. 모두 Debug 출력(배포한 플랫폼 09-22 11:27 과 해시 같음), 사람 순서로(마우스 · 키보드). ### 1. A-1 의 아홉 경우 (`e11-a1-setup.sh` · `e11-e1-a.ps1` · `e11-e1-a-verify.sh`) 모두 첫 회차에 끝. 뽑은 곳은 고른 폴더 **아래 새 폴더**, 안내는 그 옆(A-2 · A-3 설계대로). | # | A-1 때 | 지금 | |---|---|---| | 1 커밋 하나 | 2개 · 바이트 같음 | `변경분_228995f..8145f3b_2026-09-22` 에 2개 · 바이트 같음 · 안내 범위 "(고른 커밋의 부모)" | | 2 범위 | 3개 · 바이트 같음 | 3개 · 바이트 같음 · 안내에 이름 바뀜 "(옛 이름 Motion/Unit16.cs)" | | 3 지운 파일 | **어디에도 없음** | 안내 "장비에서 지워야 할 파일" 에 `지워짐 Recipe/Unit11.cs` | | 4 이름 바뀐 옛 경로 | **알 길이 없음** | 같은 목록에 `옛 이름 Motion/Unit16.cs (→ Motion/Renamed16.cs 로 바뀜)` — git 기대 지울 것 2개와 같음 | | 5 병합 커밋 | 첫 부모와만 · 화면에 없음 | 같은 동작(1개) · **안내에 범위 `37a2ced … (고른 커밋의 부모) → 84961da`** 로 무엇과 견줬는지 남음 | | 6 거꾸로 범위 | 말없이 됨 | 같은 동작(2개 · 지울 것 3개) · 안내에 방향 그대로(`37a2ced → 228995f`) | | 7 이진 · 한글 · 깊은 경로 | 바이트 그대로 | 바이트 그대로 | | 8 이미 파일이 있는 폴더 | 옛 추출 · 사용자 파일과 **섞임** | 두 번 뽑으니 **새 폴더 둘**(범위별 이름) · `사용자메모.txt` 그대로 | | 9-a · 9-b 읽기 전용 · 잠긴 파일 | **반쯤 뽑힌 채 멈춤** | 새 폴더에 써서 막힘 없이 3개 · 미리 둔 파일은 손대지 않음 | - 대조 스크립트가 경우 8 의 첫 폴더(c1 범위)를 둘째 범위와 견줘 "다름" 이라고 찍었다 — 그 폴더는 안내대로 c1 범위이고 경우 1 과 같은 내용이다(스크립트가 폴더마다 범위를 따로 안 봄). - 저장소 워킹트리 내내 Clean. ### 2. C-1 의 여덟 경우 (`e11-c1-setup.sh` · `e11-e1-c.ps1` · `e11-e1-c1again.ps1`) | # | C-1 고치기 전 | 지금 | |---|---|---| | 1 | [모든 브랜치] 에서 [마지막 메시지] 가 딴 브랜치 메시지 | 목록 맨 위 `딴 브랜치 최신 작업` 인데 칸에 **`남이 만든 커밋`**(HEAD) | | 2 | 스테이징 파일이 말없이 들어감 | 확인 창 "스테이징해 둔 파일 1개도 이 커밋에 들어갑니다" → [예] → 알림 "… · 파일 1개 포함" | | 3 | 작성자 · 작성 시각이 바뀜 | 두 번 고쳐도 작성자 `박지훈` · 작성 `2026-09-15 10:00` 그대로 | | 4 | 작업 중에도 켜져 실패 | 병합 충돌 26개 동안 **꺼짐** · 설명 "병합 · rebase · cherry-pick · revert 를 끝낸 뒤에 쓸 수 있습니다" | | 5 | (부모 둘 그대로) | [마지막 메시지] 가 `Merge branch e1-side` · 고쳐도 **부모 둘** | | 6 | 막지 않고 Push 거부 | 확인 창 "이 커밋은 origin/amend 에 이미 올라가 있습니다. 고치면 다음 Push 가 거부됩니다" → [예] 뒤 [Push] `cannot push non-fastforwardable reference` (정한 대로 묻기만) | | 7 | 새 해시만 | 알림 "커밋 수정 완료 (옛 4816f3e → 새 953816a)" | | 8 | 한 줄 칸 | 그대로(범위 밖으로 둠) | ### 3. C-2 로 이력을 다시 쓴 저장소에서 병합 한 길 (`e11-e1-merge.ps1 -Way reword`) 새 저장소의 `feature/mine` 에 커밋 둘(박지훈 · 이수진)을 얹고, 앞 커밋 `첫 추가 커밋(오타 잇음)` 을 우클릭 → [메시지 바꾸기...] 로 `첫 추가 커밋` 으로 고친 뒤 그대로 병합. - 확인 창 "… 이 커밋과 그 뒤 1개, 모두 2개가 새 해시로 다시 써집니다 …" → 알림 `메시지 바꿈 완료 (옛 HEAD e1d924c → 새 HEAD 3145f3f) · 커밋 2개 다시 씀`. - 앞 네 커밋의 작성자 · 작성 시각 · **트리 4/4 같음**, 제목은 고른 것만. 되돌릴 자리 `refs/original/20260922-115615/heads/feature/mine`. - 병합: 충돌 24(+자동 2) → 누른 Take 18 = 줄 고른 로그 18 → 병합 커밋 `ae20f56`(부모 첫째 = 다시 쓴 `3145f3f`) · 줄끝 · BOM 바뀐 파일 0 · 충돌 표식 0 · class 0 · 워킹트리 Clean · 두 탭 같은 커밋. ### 4. 다섯 길 + pull (`e11-e1-merge.ps1 -Way merge|pull|rebase|pick|revert` — 10차 E-1 과 같은 순서) | 길 | 누른 Take = 로그 | 마지막 Save 뒤 기준 | 커밋 | 줄끝 · BOM 바뀐 파일 | 충돌 표식 · class | 두 탭(10차 B-1) | 걸린 시간 | |---|---|---|---|---|---|---|---| | 병합 | 18 = 18 | HEAD · N=3 = git | `cac5366` 부모 둘 · 본문 해결 26개 | 0/33 | 0 · 0 | 같음 | 303초 | | pull | 18 = 18 | 같음 | `1b32e2f` "Merge remote-tracking branch 'origin/feature/mine' …" | 0/33 | 0 · 0 | 같음 | 303초 | | rebase | 18 = 18 | 같음 | `b108182` 부모 하나 · "내 쪽 작업" | 0/31 | 0 · 0 | 같음 | 302초 | | cherry-pick | 18 = 18 | 같음 | `631234e` "상대 쪽 작업" · 빈 cherry-pick 은 [커밋] 꺼짐 → [작업 취소] (8차 B-2) | 0/33 | 0 · 0 | 같음 | 350초 | | revert | 6 = 6 | HEAD · N=6 = git | `d59bc42` `Revert "내 쪽 작업"` · REVERT_HEAD 안 남음 | 0/36 | 0 · 0 | 같음 | 199초 | - 10차 E-1 과 숫자가 같다. **새로 걸린 것 없음.** ### 시험 도구 쪽에서 고친 것 (제품 아님) - **창을 앞으로 부르는 도우미가 최대화를 풀었다** — `ShowWindow(SW_RESTORE)` 를 늘 불러, 첫 누름 때 창이 복원 크기로 줄고 옛 자리를 눌러 로그 칸에 떨어졌다(누르기 전 · 뒤 사진으로 확인). 경우 1 이 처음에 "칸이 빔" 으로 나온 까닭이다. **최소화돼 있을 때만** 되살리게 고쳤다(`e11-c1lib.ps1` · `e11-e1-a.ps1`). 앞선 차수의 결과는 누른 뒤 자리를 다시 읽어 눌렀으므로 그대로 믿을 수 있다. - C-1 시험 저장소의 "다른 브랜치의 더 새 커밋" 날짜가 09-18 이라 오늘(09-22)에는 목록 맨 위가 HEAD 가 되어 경우 1 이 성립하지 않았다 → 12-31 로. - rebase · cherry-pick · revert 뒤 `d1-verify.ps1` 이 부모가 하나인 커밋에도 `git merge-base` 를 불러 사용법 글을 찍는다 — 판정에는 영향 없음(10차와 같음). - 이 PC 의 Caps Lock 이 켜져 있어 영문 입력이 대소문자 뒤집혀 들어갔다(경우 5 의 메시지). 키보드 상태라 바꾸지 않았다 — 판정에는 영향 없음. - 하네스 22벌 1,247건 · 플랫폼 24건 그대로 · 빌드 경고 0 · 오류 0 · 설정 파일 되돌림 해시 매번 같음. 제품 코드 변경 없음. ## E-2. 웹 문서 · 기획안을 11차에 맞게 (2026-09-22, 완료) ### MergeHub 문서 (`doc/web/index.html`, 아티팩트 "MergeHub 문서" 버전 11 → **13**) - 올리기 전에 발행본(버전 11)을 받아 로컬과 견줌 — 09-17 에 올린 그대로였고(다른 사람 손 없음), 그 뒤 로컬에서만 바뀐 것은 11차 F-12 · B-1 · B-2 문장뿐. - 고친 것: - 개요 — 09-22 기준 · 22벌 1,247건 · 11차 · 커밋 129 · 지시서 11차. - 매뉴얼 — Git 탭 표에 우클릭 [메시지 바꾸기...] 와 아래 두 절 연결, **"커밋 메시지 고치기"**(두 길을 한 표로 — 고치는 커밋 · 메시지 넣기 · 함께 들어가는 것 · 이미 올린 커밋 · 남는 것 · 꺼지는 때, 되돌리는 길), **"변경분 추출"**(새 폴더 · 옆 안내 파일 · 먼저 보고 쓰기 · 병합 커밋 · 거꾸로 범위), 목차 둘, 알아 둘 한계 셋(메시지 칸 한 줄 · 올렸는지는 마지막 Fetch 기준 · D 없는 PC 는 계정마다 설정). 실행 위치(B-1) · 설정 위치(B-2) · C# 스타일 기본 AURORA(F-12)는 먼저 적어 둔 것이 함께 올라감. - 남은 일 — 11차 표(완료 · 대기 · 진행). - 지금까지 만든 것 — 09-22 11차 기록 · 커밋 129 · 1,247건 · 하네스 막대 11차(폭을 새 최댓값으로 다시 잼) · 기능 목록 Git 한 줄 · 배포 한 줄. - 기획안 v2 — 커밋 메시지 수정 **완료**, 변경분 추출 설명, 3단계에 11차, 4단계 **진행**(베타 준비). - WinMerge 쪽 숫자 1,247건. - 대조: 문서의 단추 이름 91개를 소스(MergeHub · 플랫폼)에서 찾음 — **"맞추지 않음"(09-18 F-12 때 적은 말)이 실제 콤보 글자 "C# 스타일 끔" 과 달라** 문서 두 곳 · 이 기록 한 곳을 고침. 남은 하나(`비교 규칙 펴기` 의 공백 두 칸)는 화면에 보이는 글자가 같다. 태그 짝 모두 맞음. - 공유 링크를 받은 사람에게는 **고정된 옛 버전**이 보이도록 되어 있다 — 새 버전을 보이려면 페이지 Share 메뉴에서 사용자가 바꾼다. ### 기획안 v1.2 (잠금 아티팩트 "UbiSam MergeTool 개발 기획안" 버전 **17**) - 발행본을 받아 로컬 잠금 파일(09-17 17:06)과 견줌 — 암호문 · salt · IV 가 같음. 그러므로 고칠 원문은 09-17 원문(`plan/mergetool.html`). - 원문에서 고친 것: 3.2 Git 작업 UI화의 **커밋 메시지 수정 → 완료**("마지막 커밋은 [커밋 수정], 앞 커밋은 트리에서 우클릭 → [메시지 바꾸기]"), 변경분 파일 추출 설명(새 폴더 · 지울 파일 안내, ZIP 이 없어 "일부" 그대로), 일정 요약(09-22 기준 · 1,247건 · 4단계 베타 준비 중), 3단계 "Git 작업 버튼" 한 줄, 4단계 상태 "대기" → "준비 중", 4단계 베타 줄, 개정일 09-22. - **A4 쪽 높이**: 고치기 전 · 뒤 원문을 헤드리스 Edge 로 재니 8쪽 모두 1123px · 넘침 없음으로 같다. 기능 목록 쪽 그림으로 한 줄씩인 것 확인. - **잠금은 사용자가 했다**(`lock-plan.js`, 비밀번호는 화면에 안 보이게 받아 어디에도 남기지 않음 · 비교할 원본은 09-17 원문). 첫 "잠갔어" 때는 잠금 파일이 09-17 것 그대로여서 올리지 않고 멈췄다(PowerShell 문법을 CMD 에서 돌린 것으로 보임). 두 번째에 새 salt · IV 의 잠금 파일(13:12)이 생겨 올렸고, 발행본의 암호문이 그 파일과 같음을 되읽어 확인했다. 스크립트 출력은 다른 창이라 직접 보지 못했다. ## F-12. C# 코드 스타일 맞춤의 기본값을 AURORA 로 (2026-09-18, 완료) 사용자: "기본값은 원본형태를 따르고 C#인 경우에 AURORA 스타일로 하자" → 물어서 정한 것은 **제품 기본값 AURORA · C# 파일만 · 저장 동작은 지금 그대로**(켜져 있으면 저장도 그 스타일로 쓴다). ### 알아본 것 - C/C++ · XAML 은 고칠 것이 없었다. 스타일 맞춤은 `CSharpStyle.Applies` 가 **확장자 `.cs` 만** 보므로(`Services/CSharpStyle.cs:60`) 설정이 무엇이든 다른 파일은 원본 그대로 견준다. - 그래서 바뀐 것은 설정 기본값 한 줄뿐이다. ### 고친 것 | 자리 | 고친 것 | |---|---| | `MergeHubSettings.cs:77` | `CSharpBraceStyle` 기본값 `None` → **`Aurora`**. 왜 그렇게 정했는지와 "C# 파일에만 걸린다" 를 주석으로 남김 | | 웹 문서 매뉴얼 | "기본은 끔" → "**기본은 AURORA**(2026-09-18 결정) · 끄려면 콤보에서 [C# 스타일 끔]" · "C# 파일에만 걸린다" 한 줄 더함 | | 웹 문서 설정 표 | 기본값 칸 `끔` → `AURORA`, "`.cs` 파일에만 걸린다" | | 웹 문서 시연 대본 | "스타일 맞춤은 끔으로 둔다" → "기본이 AURORA 이므로 시연 전에 [C# 스타일 끔] 으로 바꿔 둔다" | | 하네스 `StyleTest` | **+12건(78 → 90)** — 설정 기본값이 AURORA 인지, `.cpp` · `.h` · `.hpp` · `.c` · `.xaml` · `.py` · `.txt` · `.cs.txt` 는 안 걸리는지, `.cs` · `.CS` · 한글 경로 `.cs` 는 걸리는지. 고치기 전에 먼저 넣어 **기본값 검사만 실패**하는 것을 보고 시작했다 | ### 확인한 것 — 설정 파일이 없는 첫 실행 (`e11-f12.ps1`) 설정 파일을 백업해 치우고, 중괄호 자리만 다른 짝 두 벌을 명령줄(`--diff`)로 열었다. | 무엇 | 결과 | |---|---| | C# 짝(`left.cs` Allman · `right.cs` AURORA) | 요약 **"차이 없음"** · 상태바 `무시: 머지 주석 · C# AURORA` (`e11-f12-cs.png`) | | C++ 짝(`left.cpp` · `right.cpp`, 같은 모양의 중괄호 차이) | 요약 **"남은 차이 4줄"** — 원본 그대로 (`e11-f12-cpp.png`) | | 앱이 새로 만든 설정 파일 | `"CSharpBraceStyle": 1` (= Aurora) | | 설정 파일 되돌림 | 해시 같음 | - 하네스 22벌 **1,159건** 통과(1,147 → +12) · 빌드 경고 0 · 오류 0. - 이미 설정 파일이 있는 PC 는 그 값을 그대로 쓴다. 이번 변경은 **설정이 없는 첫 실행**에만 닿는다.