Ubisam-MergeTool/doc/history/2026-09-17-10차.md
ksj09406 20d42c4aee 10차 E-2: 웹 문서를 10차 끝 기준으로 (아티팩트 버전 11)
- 발행본(버전 10)이 9차 D-1 파일과 같음을 먼저 확인
- 매뉴얼: 두 탭은 같은 커밋을 본다 · 알아 둘 한계에서 고친 둘(B-1 · C-1) 뺌
- 남은 일: 10차에서 고친 것 · 10차에 남은 것(HDD)
- 지금까지 만든 것 · 기획안 v2 일정 · WinMerge 숫자: 1,147건 · 커밋 114
- 10차 D-1 · F-3 에서 로컬로만 고친 문장도 함께 발행
- 화면 문구 grep 대조 · 태그 짝 맞음

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 16:44:46 +09:00

391 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 10차 진행 기록 (2026-09-17 ~)
지시서: [../작업지시/10차.md](../작업지시/10차.md)
## A-1. 네 칸에서 충돌을 차례로 고르는데 한 번이 남지 않아 "남은 충돌 1개" 로 멈췄다 (2026-09-17, 완료 · 고치지 않음)
**61번 되풀이해도 다시 나지 않았다.** 앱은 누른 것을 모두 받아 처리했다. 짚이는 원인은 시험 도구 쪽이라 제품 코드는 바꾸지 않았고, 시험 도구를 고쳤다.
### 무엇으로 쟀나
- 앱에 **임시 로그**를 넣었다(`[A1측정]`, 잰 뒤 `git checkout` 으로 되돌리고 다시 빌드 — 남은 줄 0 · 경고 0 · 오류 0).
[다음 충돌] 이 불릴 때 캐럿 · 고른 줄 · 옮겨 간 줄, Take Mine / Theirs 가 불릴 때 고른 줄(충돌인지 · 정할 필요가 있는지 · 주석 줄인지) · 남은 충돌 수(전 · 후),
그리고 Take 단추가 꺼지는 순간(CanExecute 가 거짓)의 고른 줄.
- 되풀이 스크립트(`d10-a1.ps1`): 새 저장소 → 병합 또는 cherry-pick([모든 브랜치]) → `Motion/Unit0.cs` 와 `Weld/Unit1.cs`(둘 다 충돌 6개)를 **편집을 버리고 번갈아 다시 열며**
[다음 충돌] → Take Theirs / Take Mine 번갈아 여섯 번. 누르기 직전에 단추가 켜져 있었는지를 적고(꺼져 있으면 누르지 않고 "꺼짐"), 앱 로그로 Take 가 몇 번 불렸는지 센다.
- 누름 간격 두 가지: **9차와 같은 간격**(다음 충돌 뒤 1.0초 · Take 뒤 1.3초 — 9차 `Click` 의 0.6초 대기 포함) · **0.1초**(사람이 빠르게 누르는 쪽).
### 결과
| 묶음 | 되풀이 | 누름(다음 충돌 · Take) | 앱이 받은 Take | 끝나지 않은 회차 | 꺼져 있던 누름 |
|---|---|---|---|---|---|
| 병합 · 9차 간격 | 7 + 14 = 21 | 126 · 126 | 126 | 0 | 0 |
| 병합 · 0.1초 | 20 | 120 · 120 | 120 | 0 | 0 |
| cherry-pick · 9차 간격 | 10 | 60 · 60 | 60 | 0 | 0 |
| cherry-pick · 0.1초 | 10 | 60 · 60 | 60 | 0 | 0 |
| **합계** | **61** | 366 · 366 | **366** | **0** | **0** |
앱 로그 전체(시작 표시 62개 · 첫 병합 묶음 8회차는 고르기 뒤 자동 조작 오류로 끊김 — 아래):
| 확인 | 값 |
|---|---|
| Take 시작 · 끝 | 372 · 372 |
| 충돌이 아닌 줄(정할 필요 없음 · 주석 줄)에서 시작한 Take — **헛돈 Take** | **0** |
| Take 한 번에 남은 충돌이 정확히 하나 줄지 않은 것 | **0 / 372** |
| [다음 충돌] 이 정할 필요가 없는 줄로 간 것 | 0 / 372 |
### 알게 된 것
- **Take 처리 중에 고른 줄이 잠깐 바뀐다.** Take Theirs 는 주석 줄을 끼워 넣고 편집기 글을 다시 채우는데, 그 사이 고른 줄이 다음 행 → 0행 → 끼워 넣은 주석 줄로 옮겨 가며
Take 단추가 꺼진다(로그 "CanTakeTheirs=false sel=0"). 모두 **한 번의 명령 실행 안에서** 일어나서(시작 · 끝 기록 사이) 다른 누름이 끼어들 틈은 없다.
끝나면 고른 줄은 주석 줄이라 Take 두 단추가 꺼진 채로 있고, [다음 충돌] 을 눌러야 다시 켜진다.
- 그래서 **Take 뒤 [다음 충돌] 이 처리되기 전에 Take 단추를 보면 꺼져 있다.** 9차 시험 도구의 `Click` 은 단추가 그 순간 꺼져 있으면 **누르지 않고 False 를 돌려주는데,
9차 스크립트(`ResolveAll`)는 그 값을 버렸다.** 기계가 바빠 [다음 충돌] 처리가 늦으면 고르기 한 번이 말없이 빠진다 — 9차 D-1 N1 의 "로그 10줄 · 남은 충돌 1개" 와 모양이 같다.
사람이 누르면 흐린 단추를 누른 것이라 아무 일도 안 일어난 것이 보이고, "남은 충돌 1개" 와 [다음 충돌] 로 남은 곳을 찾는다.
- 9차 첫 회차는 앱 로그가 없어 이것이 원인이었다고 **확정하지는 못했다.** 다만 앱 쪽에서는 61회 동안 누름을 놓치거나 헛돈 적이 없다.
### 고친 것 (시험 도구)
- `d7lib.ps1` `ResolveAll` — Take 누름이 꺼져 있어 안 눌리면 1.2초 기다렸다 한 번 더 누르고, 그래도 안 되면 결과에 "(못 누름)" 을 남긴다. 말없이 빠지지 않는다.
- 제품 코드 변경 없음. 하네스는 그대로(22벌 1,122건).
### 시험 도구 쪽 (제품 결함 아님)
- 첫 병합 · 9차 간격 묶음이 8회차에서 UI 자동화 조회 오류(`ElementNotAvailableException`, 화면 요소 훑기 중)로 끊겼다. 모자란 만큼 14회를 더 돌렸다.
- 되풀이 스크립트 매개변수 `$Tag` 가 `WithSettings` 의 `$tag` 와 겹쳐(PowerShell 은 대소문자를 가리지 않는다) `$Label` 로 바꿨다 — 9차 A-2 와 같은 실수.
## B-1. Git 탭 이력에서 고른 커밋을 파일 비교 탭이 새로고침 전까지 따라오지 않는다 (2026-09-17, 완료)
사용자 결정(2026-09-17): **바로 따라간다(양방향)** · 파일 비교 탭에 저장 안 한 편집이 있으면 **고르는 순간 묻는다**.
("두 탭을 따로 둔다" · "따라가지 않고 알린다" 는 고르지 않음.)
### 고치기 전에 다시 났다 (새로 만든 저장소)
| 순서 | 결과 |
|---|---|
| Git 탭 이력에서 `바탕` 을 고름 | Git 탭은 `바탕`. 파일 비교 탭은 위 줄 Selected Commit · 왼쪽 이력 선택 · BASE 제목 모두 **`내 쪽 작업` 그대로** |
| 파일 비교 탭 [새로고침] | 그제야 `바탕` 으로 따라옴 |
| **반대로** 파일 비교 탭 이력에서 `바탕` 을 고름 | Git 탭 이력은 **`내 쪽 작업` 에 선택 표시가 남음** |
| 그 상태에서 Git 탭 [Revert] | 로그 "revert 시작: `바탕`" — **화면에 선택돼 보이는 `내 쪽 작업` 이 아니라 `바탕` 을 되돌림**, 충돌 34건(시험 저장소, 뒤에 버림) |
반대 방향이 더 위험했다 — 화면에 보이는 것과 다른 커밋에 Git 작업(Revert · Cherry-pick · Reset)이 걸린다.
### 원인
- 두 탭은 같은 값(`GitWorkspace.SelectedCommit`)을 쓰지만, 고른 쪽 뷰모델만 화면을 바꾸고 다른 쪽은 **새로고침 알림(`Refreshed`)** 으로만 다시 읽었다.
### 고친 것
- `GitWorkspace` — `CommitChosen` 알림(고른 쪽을 인자로)과 `ConfirmLeaveCommit`(파일 비교 화면이 앉히는 확인. 답: null 물을 편집 없음 · true 물었고 계속 · false [취소]).
- `CommitSelection.IsOtherCommit` — 사람이 **다른 커밋**을 고른 것인지(목록이 비워지며 들어온 null · 같은 해시의 새 객체는 아님). 하네스 `MergeSaveTest` 4건(210건).
- `HomeViewModel` — 파일 비교 탭에서 고르면 `CommitChosen` 을 내고, 다른 쪽이 고르면 왼쪽 이력 · Selected Commit · 두 칸을 **게이트가 빈 뒤에** 다시 세운다(`RebuildListAfterRefreshAsync`).
확인 창을 띄울지(`WillAskBeforeDiscard`)를 `ConfirmDiscard` 에서 떼어 둘이 같은 조건을 쓴다.
- `GitViewModel` — 고르면 `CommitChosen`. 파일 비교 탭이 고르면 이력 선택 표시 · 단추가 따라가고, **커밋 내용(diff)은 Git 탭이 다시 보일 때** 그린다(`ShowPendingDiff`).
- `GitView` — 이력 목록(`HistoryList`)이 **선택을 바꾸기 전에**(마우스 누름 · ↑↓ Home End PageUp PageDown) 묻는다. [취소] 면 그 누름을 막고, 물은 뒤 [계속] 이면 화면이 그 커밋을 직접 고른다.
### 고치며 걸린 것 (최종 모양에 이른 까닭)
| 해 본 것 | 걸린 것 |
|---|---|
| 다른 쪽이 고르면 바로 `LoadCommitAsync` | Git 탭이 커밋 내용을 그리느라 작업 게이트를 쥐고 있어 파일 비교 탭 읽기가 **건너뛰어짐** — Selected Commit 만 바뀌고 BASE 는 옛 커밋 |
| 선택 바인딩 setter 안에서 확인 창 | 창이 닫힌 뒤 목록이 선택을 다시 밀어 넣어 **[취소] 해도 창이 한 번 더** 뜸 |
| setter 에서 미뤄 묻고 [취소] 면 변경 알림 · `SelectedItem` 다시 넣기 · `SetCurrentValue`(ContextIdle) | 코드상 `SelectedItem` 은 돌아오는데 **목록은 `바탕` 을 선택으로 남김**(UI 자동화 SelectionPattern · 화면 모두). `SelectedItem = …` 은 바인딩을 떼어 내기까지 함 |
| **선택이 바뀌기 전에** 묻고 누름을 막음 | [취소] 는 맞음. 그런데 [계속] 이어도 **창이 누름을 끊어 목록이 고르지 않음** → 물었으면 화면이 직접 고르게 해서 끝 |
### 확인한 것 (고친 앱, 사람 길 — 목록은 마우스 누름 · 방향키, `d10-b1-after.ps1` · `d10-b1-cancel.ps1` · `d10-b1-diff.ps1`)
| 경우 | 결과 |
|---|---|
| Git 탭에서 `바탕` | 파일 비교 탭 Selected Commit · 왼쪽 이력 · **BASE 제목까지** `바탕` |
| 파일 비교 탭에서 `내 쪽 작업` | Git 탭 이력 선택 `내 쪽 작업` |
| 편집 있음 · Git 탭에서 `바탕` 누름 → [취소] | 창 한 번(“Common/Util/Unit103.cs 에 저장하지 않은 편집이 있습니다. 다른 커밋을 봅니다.”) · 두 탭 · 목록 자체(SelectionPattern) 모두 `내 쪽 작업` · 다시 뜨는 창 없음 |
| 편집 있음 · `바탕` 누름 → [저장하지 않고 계속] | 두 탭 `바탕` · 워킹트리 바뀐 파일 0(편집 버려짐) |
| 편집 있음 · 같은 커밋 누름 | 창 안 뜸 |
| 편집 있음 · ↑ → [취소] / ↑ → [계속] | 그대로 `바탕` / 두 탭 `내 쪽 작업` |
| 파일 비교 탭에서 `내 쪽 작업` → Git 탭 [Revert] | 로그 "revert 시작: `내 쪽 작업`" — **보이는 커밋** |
| 파일 비교 탭에서 `바탕` → Git 탭으로 옴 | Git 탭 커밋 내용 머리 `… 바탕` |
| 9차 A-2 흐름(cherry-pick 1회, `d9-a2.ps1`) | 시작 · 파일 단위 = 고른 커밋 · Save 뒤 = HEAD · 커밋 뒤 = 새 HEAD — **맞음** |
- 하네스 22벌 1,126건 통과(+4) · 빌드 경고 0 · 오류 0. 임시 로그(`[B1측정]`)는 모두 걷어냄(남은 줄 0).
### 남긴 것
- UI 자동화의 `SelectionItemPattern.Select()` 처럼 **마우스 · 키보드를 거치지 않고** 목록 선택을 바꾸면 묻지 않고 따라간다(사람 길이 아님).
- 처음 켰을 때 Git 탭 커밋 내용 칸이 비어 있는 것은 전부터 그렇다(이력에서 고르면 그려진다).
## C-1. "머지 주석 무시" 를 끈 채 다시 정렬하면 반영 색이 옆 줄로 옮겨 간다 (2026-09-17, 완료)
### 고치기 전에 다시 났다 (새로 만든 저장소, 병합 → `Weld/Unit1.cs` 네 칸, `d10-c1.ps1`)
설정 `IgnoreMergeNotes` 를 끄고(켬도 같이 잼) 첫 충돌 Take Theirs → 비교 규칙 [Aa] 두 번(다시 정렬) → 나머지 5개 Take Theirs → 다시 정렬 두 번 → [Save].
| 때 | 규칙 끔 범례 | 규칙 켬 범례 |
|---|---|---|
| Take Theirs 직후 | 머지 반영함 1 · 추가 1 | 머지 반영함 1 · 무시 1 |
| 다시 정렬 뒤 | 머지 반영함 1 · **직접 수정 1** · 추가 0 | 같음 |
| 여섯 모두 Theirs | 머지 반영함 6 · 추가 6 | 머지 반영함 6 · 무시 6 |
| 다시 정렬 뒤 | 머지 반영함 6 · **직접 수정 6** · 추가 0 | 같음 |
| Save 한 파일 | 3793줄 · 주석 6 · SHA256 `6FE4994D…` | 같은 해시 |
- 규칙 끔에서 다시 정렬하면 초록(반영함)이 **주석 줄**에, 보라(직접 수정)가 **반영한 코드 줄**에 붙었다. 요약 · 줄 수 · 저장 내용은 같았다.
### 원인
- 주석 줄과 코드 줄이 한 행에 짝지어진 것을 떼어 놓는 `NoteRows.SplitFour` 를 **규칙이 켜져 있을 때만** 했다(6차 B-5).
끄면 정렬기가 MERGED 의 주석 줄을 BASE 의 코드 줄(`Power93`)과 한 행에 두고, 반영한 코드 줄은 BASE 없는 다음 행으로 밀린다.
- 반영 표시는 **BASE 줄 번호**로 붙들어 두므로(`_appliedBaseNumbers`) 주석 행에 붙고, BASE 없는 코드 행은 글이 바뀐 줄이라 "직접 수정" 이 됐다.
- 덧: 다시 정렬할 때 우리 주석 줄을 `IsApplied = true` 로 두어, 떼어 놓기만 고치면 이번에는 주석 줄도 "머지 반영함" 이 되어 반영 수가 두 배(12)로 셌다.
### 고친 것
- `HomeViewModel.BuildThreeWayLines` — 네 칸은 규칙과 상관없이 `NoteRows.SplitFour` 로 떼어 놓는다. 무시할지(색 · 차이 수)는 규칙이 따로 정한다.
- `HomeViewModel.ReloadLinesFrom` — 다시 만든 줄이 우리 주석 줄이면 `IsMergeNote` 만 되찾고 **"반영함" 으로 칠하지 않는다**(넣는 순간과 같은 모양 - 9차 B-1 과 같은 원칙). "직접 수정" 으로도 치지 않는다.
- **두 칸은 규칙을 끄면 떼어 놓지 않는 그대로 둔다** — 아래 "두 칸도 떼어 봤다".
- 하네스 `NoteTest` 5건(74건): 비교 키 없이(규칙 끔) 정렬하면 주석 줄과 코드 줄이 한 행에 섞이고, 떼어 놓으면 주석 줄은 혼자 서고 반영한 코드 줄이 BASE(2행) · MINE · REMOTE 와 한 행이 된다.
### 두 칸도 떼어 봤다 → 되돌림
규칙 끔 · 두 칸 비교(Git 아님, `d10-c1-two.ps1`) — 주석만 끼어든 줄 · 주석 + 코드 고침 · 줄 끝 주석을 한 파일에:
| 빌드 | 연 뒤 | 다시 정렬 뒤 |
|---|---|---|
| 고치기 전 | 남은 차이 4줄 | 2줄 (반영함 2 · 추가 1) |
| 두 칸도 늘 떼어 놓음 | **5줄** (삭제 1 이 새로 생김) | **3줄** |
| 최종(두 칸은 규칙 켤 때만) | 4줄 | 2줄 (반영함 0 · 추가 2 — 주석 줄을 반영함으로 안 칠함) |
| 규칙 켬(세 빌드 모두) | 1줄 | 1줄 |
- 규칙을 끄면 주석 줄에 비교 키가 없어 **정렬기가 이미 한 줄씩 밀려 짝짓는다**(`int Speed3 = 303;` ↔ `int Speed2 = 222;`). 떼어 놓아도 밀린 짝은 풀리지 않고 한 줄이 더 갈라졌다.
두 칸에는 반영 표시를 BASE 줄 번호로 붙드는 일도 없어 되돌렸다.
### 확인한 것 (최종 빌드)
| 네 칸 · `Weld/Unit1.cs` | 규칙 끔 | 규칙 켬 |
|---|---|---|
| Take Theirs 직후 → 다시 정렬 뒤 | 반영함 1 · 추가 1 → **반영함 1 · 추가 1** | 반영함 1 · 무시 1 → 같음 |
| 여섯 모두 → 다시 정렬 뒤 | 반영함 6 · 추가 6 → **반영함 6 · 추가 6** | 반영함 6 · 무시 6 → 같음 |
| 요약 · 총 줄 수 | 고치기 전과 같음(남은 충돌 5 → 충돌 정리 끝 · 3788 → 3793줄) | 같음 |
| Save 한 파일 | 3793줄 · 주석 6 · SHA256 `6FE4994D…` (고치기 전과 같음) | 같음 |
| 화면(다시 정렬 뒤) | 주석 줄 파랑(추가) · 반영한 코드 줄 초록 · BASE `Power93` 은 코드 줄과 한 행 | - |
- 하네스 22벌 1,131건 통과(+5) · 빌드 경고 0 · 오류 0. 설정은 시험마다 백업 → 되돌림(해시 같음).
### 남긴 것
- 규칙을 끈 두 칸 비교에서 주석 줄이 끼어들면 정렬이 한 줄씩 밀리는 것(위 표의 `Speed3` ↔ `Speed2`)은 규칙을 끈 이상 비교 키가 없어 생기는 모양이라 그대로 둔다. 기본값(켬)에서는 나지 않는다.
## D-1. 그날 첫 큰 폴더 비교가 9.2초 (2026-09-17, 완료 · 고치지 않음)
**9.2초는 다시 나지 않았다.** 파일 캐시를 비운 첫 비교도 0.5초 안팎으로 데운 상태와 같았다. 줄일 자리가 없어 제품 코드는 바꾸지 않았고, 매뉴얼 "알아 둘 한계" 를 잰 값으로 고쳤다.
### 무엇으로 쟀나
- 5차 B-2 시험 묶음(`%TEMP%\mergehub-perf`, 4,500개 · 양쪽 8,922개 · 136MB). 이 PC 디스크는 **NVMe SSD**(INTEL SSDPEKNU010TZ) · 논리 CPU 16개.
- **차가운 상태 만들기**: 재부팅 · 시스템 도구(대기 메모리 비우기)는 쓰지 않았다. 파일마다 **버퍼 없이(`FILE_FLAG_NO_BUFFERING`) 한 번 열었다 닫아** 그 파일의 캐시를 비웠다.
먹는지 먼저 확인: 크기가 같은 4,063쌍을 한 갈래로 읽기 — 데운 뒤 407 · 386ms → **비운 뒤 1,808ms** → 곧바로 다시 396ms. 먹는다.
- 측정 프로그램 `ColdPerf`(앱의 `FolderComparer` 를 그대로 컴파일, 앱 코드 변경 없음) · 앱에서는 비운 뒤 새로 켜서 [비교](`d9-b2.ps1`).
- 백신 CPU 시간도 재려 했으나 `MsMpEng` 프로세스 시간은 권한 때문에 읽히지 않았다(설정은 건드리지 않음).
### 잰 값
| 경우 | 전체 비교 | 빠른 비교(크기 · 수정일) |
|---|---|---|
| 데운 상태 | 479ms | 159ms |
| 캐시 비운 뒤 1 · 2 · 3회 | **535 · 455 · 494ms** | 172 · 154 · 193ms |
| 비운 뒤 곧바로 한 번 더 | 562 · 406 · 475ms | - |
결과 요약은 모든 경우 글자 하나까지 같았다(`전체 4500개 · 다름 359(주석만 294) · 왼쪽만 40 · 오른쪽만 38 · 같음 4063`).
크기가 같은 4,063쌍을 **끝까지 읽기만**(캐시 비운 뒤, 갈래 수별):
| 갈래 | 1 | 4 | 16(논리 CPU 수) | 32 | 64 |
|---|---|---|---|---|---|
| ms | 1,775 | 583 | 318 | 305 | 332 |
앱(비운 뒤 새로 켬, 자동 조작으로 누른 때부터 요약이 뜰 때까지 — 누름 뒤 0.6초 대기 포함):
| 회 | 첫 [비교] | 둘째 | 셋째 |
|---|---|---|---|
| 1 | 1,760ms | 1,457ms | 1,414ms |
| 2 | 1,051ms | 1,459ms | 1,458ms |
### 판단
- **파일 캐시가 비어도 여러 갈래로 읽어서 몇백 ms 차이에 그친다**(한 갈래였다면 0.4 → 1.8초). 폴더 비교는 이미 64개가 넘으면 여러 갈래로 가린다(5차 B-2).
- 앱을 새로 켠 직후 첫 비교도 느리지 않다 — 앱 쪽 첫 실행 값(JIT 등)도 아니다.
- 9차 B-2 의 9.2초는 **며칠 손대지 않은 묶음을 그날 처음** 비교한 값이었다. 파일 캐시 말고 남는 것은 디스크 정보(폴더 목록 · MFT) 캐시, 백신 검사(서명 갱신 뒤 다시 검사 등)인데
둘 다 재부팅이나 시스템 · 보안 설정 없이는 다시 만들 수 없어 가리지 못했다.
- **고치지 않는다.** 다시 나지 않는 것을 짐작으로 고치지 않는다(공통 규칙). 결과가 바뀌는 길(빠른 비교를 기본으로)은 하지 않는다.
### 고친 것 (문서)
- 웹 문서 매뉴얼 "알아 둘 한계" — "첫 비교 9.2초 · 두 번째부터 0.7초" 를 잰 값(캐시 비운 첫 비교도 약 0.5초, 한 갈래라면 0.4 → 1.8초, 9.2초는 한 번 났으나 다시 안 남, HDD 는 재 보지 않음)으로. 발행은 E-2 에서 함께 한다.
### 남긴 것
- **느린 디스크(HDD · SATA SSD)에서는 재 보지 않았다.** 이 PC 는 NVMe 뿐이다. 한 갈래 1.8초가 여러 갈래로 0.3초가 된 것은 NVMe 가 동시 읽기에 강해서이고,
HDD 에서는 여러 갈래 읽기가 오히려 느릴 수 있다. 사내 PC 가 HDD 라면 베타 배포 때 재 볼 거리다.
## E-1. 다섯 길(+ pull)을 다시 끝까지, 누름 간격은 사람 손 빠르기로 (2026-09-17, 완료)
지시서대로 **고치지 않고 적기만 했다.** 제품 코드는 바꾸지 않았다. **다섯 길 모두 끝까지 갔고 새로 걸린 것은 없다.**
### 무엇으로 했나 (`d10-e1.ps1 -Way merge|pull|rebase|pick|revert`)
- 길마다 `C1Repo` 로 저장소를 새로 만들고 **파일 비교 탭을 미리 열지 않았다**(`D7_NO_PREOPEN=1`). 이름 창은 [저장], 원격 영역은 [펴기]. 설정 `CSharpBraceStyle` 은 길마다 백업 → 끔 → 되돌림(다섯 번 모두 해시 같음).
- 푸는 순서는 9차 D-1 과 같다: 같은 줄 충돌 15개 파일 단위 Accept Theirs → NewPanel Accept Both [아니오] → [3분할로 열기] 뒤 저절로 열리는 파일마다 [다음 충돌] → Take Theirs / Take Mine 번갈아(누름 사이 0.4초 · 0.7초) → [Save] · 띠 [파일 지우기] · [파일 남기기]. 마지막 `Weld/Unit1.cs` 는 네 칸.
- pull 은 bare 저장소를 원격으로 두고 원격 `feature/mine` 을 `상대 쪽 작업` 으로 옮겨 놓은 뒤 [Pull](9차 D-1 에서 빠진 길).
- cherry-pick · revert 는 [모든 브랜치] 를 켜고 **Git 탭 이력 줄을 마우스로 눌러** 골랐다(10차 B-1 은 목록이 선택을 바꾸기 전에 묻는 길이라 UI 자동화 Select 로는 그 길을 안 탄다). revert 는 15개 파일 단위 · 마지막 `Motion/Unit0.cs` 네 칸 Take Theirs 6.
- 새로 넣은 확인
- **누른 수 = 줄 고른 로그**: 시험 도구가 Take 를 실제로 누른 횟수(단추가 꺼져 누르지 못한 것은 빼고 다시 누름, 10차 A-1)를 세어 앱 로그의 "N행 … 반영 / 으로 정함" 줄 수와 견줌.
- **범례**(저장 전): 반영하며 넣은 주석 줄이 "추가" · "직접 수정" 으로 세지지 않는가(9차 B-1 · 10차 C-1 회귀).
- **B-1**: 끝낸 뒤 Git 탭 이력에서 `바탕` 을 마우스로 고르고 파일 비교 탭을 봄 → 다시 HEAD 를 고르고 봄.
### 다섯 길의 결과
| 확인 | ① 병합 | ② pull | ③ rebase | ④ cherry-pick ([모든 브랜치]) | ⑤ revert ([모든 브랜치]) |
|---|---|---|---|---|---|
| 시작 알림 | 충돌 24건 (머지 주석만 다른 2건은 자동으로 풀림) | 같음 | 같음 + [계속] 안내 | 같음 + [커밋] 안내 | 충돌 16건 + [커밋] 안내 |
| **누른 Take = 줄 고른 로그** | **18 = 18** | **18 = 18** | **18 = 18** | **18 = 18** | **6 = 6** |
| "3-Way 안 씀" 로그 · 다시 누름 · 못 누름 | 0 · 0 · 0 | 0 · 0 · 0 | 0 · 0 · 0 | 0 · 0 · 0 | 0 · 0 · 0 |
| 네 칸 REMOTE | feature/theirs | feature/theirs | 다시 올리는 내 커밋 | 가져오는 커밋 `상대 쪽 작업` | 되돌리는 커밋 `내 쪽 작업` |
| 충돌 남은 채 Save & Commit | 막힘 · git 그대로 | 막힘 · git 그대로 | 꺼짐 | 꺼짐 | - |
| 범례(Unit0 · Unit1, Take 6번) | 반영함 6 · 직접 수정 0 · 추가 0 · 무시 3 | 같음 | 같음 | 같음 | 반영함 6 · 직접 수정 0 · 추가 0 · 무시 6 |
| 마지막 [Save] 한 파일 | Weld/Unit1.cs (네 칸) | Weld/Unit1.cs | Weld/Unit1.cs | Weld/Unit1.cs | Motion/Unit0.cs (네 칸) |
| 마지막 Save 뒤 제목 | `4588370 · Weld/Unit1.cs · 병합 전 내 쪽` | `0bb5489 · … · 병합 전 내 쪽` | `6798ad6 · … · 올릴 자리` | `3501248 · … · 가져오기 전 내 쪽` | `0454fdc · Motion/Unit0.cs · 되돌리기 전 내 쪽` |
| 마지막 Save 뒤 요약 | 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 3줄 | 같음 | … · [계속] 으로 rebase 를 이어 갑니다 · 올릴 자리 대비 올린 변경 3줄 | … · [커밋] 으로 cherry-pick 을 끝냅니다 · 내 쪽 대비 가져온 변경 3줄 | … · [커밋] 으로 revert 를 끝냅니다 · 내 쪽 대비 되돌린 변경 6줄 |
| 기준 대조 (HEAD = 제목 = Selected Commit, N = git) | **같음** · +3 −3 (주석 3 뺌) | **같음** · +3 −3 | **같음** · +3 −3 | **같음** · +3 −3 | **같음** · +6 −6 (주석 6 뺌) |
| 끝낸 커밋 | `e7edade` 부모 둘 · 본문 **충돌 해결 26개 · 김승준** | `583851e` 부모 둘 · Merge remote-tracking branch 'origin/feature/mine' · 본문 **26개** · 원격 대비 뒤 0 앞 2 | `7edd15a` 부모 하나(`6798ad6` 올릴 자리 위) | `42c3d55` 부모 하나 · 작성자 **박지훈** · 커밋한 사람 시험 | `b8acc3a` Revert "내 쪽 작업" · REVERT_HEAD 없음 |
| 커밋 뒤 파일 비교 탭 기준 | 새 HEAD `e7edade` | 새 HEAD `583851e` | 새 HEAD `7edd15a` | 새 HEAD `42c3d55` | 새 HEAD `b8acc3a` |
| **B-1** Git 탭에서 `바탕` → 파일 비교 탭 | Selected Commit · 왼쪽 이력 · 제목 모두 `바탕` · 남은 차이 6줄 | 같음 | 같음 | 같음 | 모두 `바탕` · 차이 없음 (아래) |
| **B-1** Git 탭에서 다시 HEAD → 파일 비교 탭 | Selected Commit · 왼쪽 이력 · 제목 모두 HEAD | 같음 | 같음 | 같음 | 같음 |
| 줄끝 · BOM · 인코딩 바뀐 파일 | **0 / 33** | **0 / 33** | **0 / 31** | **0 / 33** | **0 / 36** |
| 충돌 표식 · class 이름 다른 Unit | 0 · 0 | 0 · 0 | 0 · 0 | 0 · 0 | 0 · 0 |
| 끝난 뒤 | Clean · `.git` 표시 없음 | 같음 | Clean · rebase-merge 없음 | Clean · CHERRY_PICK_HEAD 없음 | Clean |
| 빈 cherry-pick (방금 만든 HEAD 를 다시) | - | - | - | [커밋] **꺼짐** · "cherry-pick 했지만 가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다" · [작업 취소] 로 나옴 | - |
| 걸린 시간 | 302초 | 304초 | 300초 | 347초(빈 cherry-pick 포함) | 198초 |
- revert 의 `바탕` 대 HEAD `Motion/Unit0.cs` 는 git 으로 보면 +6 줄인데 6줄 모두 `// [김승준] 2026-09-17` 머지 주석이다. 설정 "머지 주석 무시" 가 켜져 있어 차이 없음이 맞다.
- cherry-pick · revert 는 Git 탭에서 커밋을 고른 뒤(B-1 로 파일 비교 탭도 그 커밋을 따라감) 작업을 시작했는데, [3분할로 열기] 로 처음 연 파일 비교 탭은 고른 충돌 파일을 보였고 마지막 Save 뒤 기준은 HEAD 였다(9차 A-1 규칙 그대로).
### 판정 기준
| 기준 | 결과 |
|---|---|
| 다섯 길 모두 MergeHub 만으로 끝까지 | **됐다** — 모두 첫 회차 |
| 줄끝 · BOM 바뀐 파일 0 · 충돌 표식 0 · class 이름 다른 Unit 파일 0 | **다섯 길 모두 0** |
| 마지막 [Save] 뒤 제목 · 요약 · 기준이 같다 | **다섯 길 모두 같음** — 요약의 N 도 git diff 와 같음 |
| 줄 고른 로그 = 누른 수 | **다섯 길 모두 같음** (18 · 18 · 18 · 18 · 6), 다시 누름 · 못 누름 0 |
| 8차 A-1 (처음 연 파일 비교 탭이 다른 파일) | **안 남** — [3분할로 열기] 로 처음 열어도 고른 파일, class 이름 검사 0 |
| 8차 B-1 (rebase · cherry-pick 마지막 저장 뒤 남은 차이) | **안 남** — "올릴 자리 대비 올린 변경 3줄" · "내 쪽 대비 가져온 변경 3줄" = git |
| 8차 B-2 (빈 cherry-pick [커밋] 켜짐) | **안 남** — 꺼짐 · 안내 로그 · [작업 취소] |
| 8차 F-1 (병합 커밋 본문) | 병합 · pull 본문 26개 = 처음 충돌 수 |
| 9차 A-1 · A-2 (작업 끝 기준 HEAD · 다른 브랜치 커밋이 기준) | **안 남** — [모든 브랜치] 켠 cherry-pick · revert 도 마지막 Save 뒤 HEAD, 커밋 뒤 새 HEAD |
| 9차 B-1 (넣은 주석 줄이 "추가") | **안 남** — 범례 추가 0 · 직접 수정 0, 넣은 주석은 무시로 셈 |
| 10차 B-1 (두 탭 고른 커밋) | 다섯 길 모두 Git 탭에서 고르면 파일 비교 탭의 Selected Commit · 왼쪽 이력 · 제목이 바로 따라옴 |
### 남긴 것 (시험 도구 쪽, 제품 아님)
- 줄끝 검사 스크립트(`d1-verify.ps1`)가 부모 하나인 커밋(rebase · cherry-pick · revert)에서 둘째 부모가 없어 `git merge-base` 오류를 한 번 찍는다. 첫 부모와 견주는 검사 값(0 / 31 · 33 · 36)은 그대로 나온다.
- 파일 비교 탭 요약을 읽는 함수가 "차이 없음" 글자는 잡지 않아 커밋 뒤 요약 칸이 빈칸으로 적혔다. 제목이 새 HEAD 인 것으로 판정했다.
## E-2. 웹 문서를 10차에 맞게 (2026-09-17, 완료)
`doc\web\index.html` 은 9차 D-1(아티팩트 버전 10)에서 멈춰 있었고, 10차 D-1 · F-3 에서 로컬로만 고친 문장(첫 폴더 비교 한계 · "다름(코드는 같음)" · F-1 · F-2 설명)이 발행되지 않은 채였다.
### 먼저 발행본을 읽음
- 같은 주소의 발행본(버전 10)을 읽어 저장소의 9차 D-1 커밋(`85f35b9`) 파일과 견줌 — 게시용 겉틀(앞 한 줄 · 뒤 `</body></html>`)만 다르고 본문은 같다. 다른 곳에서 고친 것이 없어 로컬 파일을 그대로 올렸다.
### 고친 것
| 자리 | 고친 것 |
|---|---|
| 개요 | 출처 `작업지시/10차.md` · 하네스 **22벌 1,147건** · "10차 끝 · 누른 수 = 줄 고른 로그" · 로컬 커밋 **114**(이 기록 커밋 포함) · 남은 일 카드 "7차 ~ 10차" |
| 매뉴얼 · Git 탭 | 새 문단 "두 탭은 같은 커밋을 본다" — Git 탭에서 고르면 파일 비교 탭이, 파일 비교 탭에서 고르면 Git 탭이 바로 따라감 · [Revert] · [Cherry-pick] 은 보이는 커밋에 · 저장 안 한 편집이 있으면 고르는 순간 "다른 커밋을 봅니다" · [취소] 면 선택 그대로(10차 B-1) |
| 매뉴얼 · 알아 둘 한계 | 9차에 더한 넷 중 **고친 둘을 뺌**: Git 탭 고른 커밋을 새로고침 전까지 안 따라옴(B-1) · 규칙 끈 채 반영 색이 옆 줄로(C-1). 본문 해결 내역은 MergeHub 에서 푼 것만 · 첫 폴더 비교(D-1 잰 값)는 남김 |
| 발표 · 남은 일 장 | "9차 · 10차: 두 칸 기준 · 두 탭 같은 커밋 · 다섯 길 누른 수 = 로그 — 끝" 한 줄 |
| 남은 일 | 머리말 "10차까지" · 새 표 "10차에서 고친 것"(A-1 · B-1 · C-1 · D-1 · E-1 · E-2 · F-1 · F-2 · F-3) · "10차에 남은 것"(HDD 에서 폴더 비교 · E-1 새로 걸린 것 없음) |
| 지금까지 만든 것 | 머리말 · 숫자(114 · 1,147) · 차수별 기록에 10차 · 하네스 막대에 10차 1,147(막대 폭 다시 계산) · 기능 목록 Git 에 두 탭 같은 커밋 |
| 기획안 v2 | 개발 기간 "09-17 지금 3단계 끝" · 3단계 줄에 8차 완료 · 9차 · 10차 완료 |
| WinMerge 비교 | "22벌 1,122건" → 1,147건 |
### 확인한 것
- **화면 문구와 대조**(앱 소스 grep): "다른 커밋을 봅니다" · "저장하지 않고 계속" · "다름(코드는 같음)" · "같음(스타일만 다름)" · "같음(머지 주석만 다름)" · "모든 브랜치" · "Selected Commit" 모두 소스에 있다.
- 옛말이 남지 않았다: "새로고침 전까지 따라오지" · "반영 색이 옆 줄" 0건. "1,122건" 은 9차 연표 한 곳(그때 값)뿐.
- 태그 짝: section 26/26 · div 198/198 · table 29/29 · ul 36/36 · ol 11/11 · li 201/201 · tr 233/233 · td 556/556 · pre 11/11 · code 71/71 · h2 38/38 · h3 26/26 · h4 24/24 · p 53/53. 제어 문자 0.
- 발행: 같은 주소의 아티팩트를 **버전 11** 로 갱신("10차 끝 기준"). 저장소의 `doc/web/index.html` 과 같은 파일이다.
- 공유 링크로 보는 사람은 고정된 예전 버전을 본다고 나온다 — 새 버전을 보이려면 공유 메뉴에서 고정 버전을 옮겨야 한다.
제품 코드는 바꾸지 않았다.
## F-1 · F-2. 폴더 비교 "같은 것만" 에 내용이 다른 것처럼 보이는 줄이 섞인다 (2026-09-17, 추가 요청, 완료)
사용자: "방금 폴더비교에서 같은것만 보기를 눌렀을때 내용이 다른파일들이 보이던데" — 9차 B-2 · 10차 D-1 에서 4,500개 시험 묶음으로 필터를 바꿔 가며 잴 때 화면으로 본 것.
사용자 결정(2026-09-17): 설정으로 같음이 된 파일은 **같음으로 두고 따로 표시**.
### 먼저 가렸다 — 비교 판정인가, 화면인가
**비교 판정**: `FolderComparer` 를 설정 네 가지 조합으로 돌려 "같음" 인데 바이트가 다른 파일을 까닭별로 셌다(`SameCheck`, 앱 코드 그대로).
| 작은 짝 13개 | 스타일 끔 · 주석 무시 끔 | 끔 · 켬 | Allman · 끔 | Allman · 켬(사용자 설정) |
|---|---|---|---|---|
| 01 같음 | 같음 | 같음 | 같음 | 같음 |
| 04 중괄호 자리만 | 다름 | 다름 | **같음** | **같음** |
| 06 머지 주석 줄만 | 주석만 다름 | **같음** | 주석만 다름 | **같음** |
| 05 코드 값 · 11 중괄호 + 코드 값 · 10 txt 값 | 다름 | 다름 | 다름 | 다름 |
| 02 BOM · 03 줄끝 · 07 인코딩 · 08 끝 공백 · 09 주석 · 12 빈 줄 · 13 들여쓰기 | 주석만 다름 | 주석만 다름 | 주석만 다름 | 주석만 다름 |
- **코드 값이 다른 파일은 어느 설정에서도 "다름"** — 판정은 설계대로(6차 B-5 · E-1). 시험 묶음 4,500개는 두 설정 모두 "같음인데 바이트가 다른 파일" 0개.
**화면**: 같은 조건(사용자 설정 그대로, 시험 묶음)으로 "같은 것만" 을 거니 파일 줄은 모두 "같음" · 양쪽 크기가 같았는데,
**폴더 줄(Config · Io · Log · Motion · Recipe · Ui · Vision · Weld)이 "다름" 에 주황 바탕**이었다(스크린샷 `d10-same-perf.png`). 사용자가 본 "다른 것" 은 이 줄이다.
작은 짝에서는 `06_머지주석만.cs` 가 크기 67B · 102B 인데 "같음" 이라 크기만 보면 다른 파일로 읽혔다(`d10-same-d10same.png`).
### 원인
- **F-1**: 필터는 "안에 걸리는 것이 하나라도 있는 폴더" 를 남기는데, 폴더 줄은 폴더 자신의 상태(`FolderStatus` — 자식 중 하나라도 같음이 아니면 "다름")로 글자 · 색을 정했다.
- **F-2**: 설정으로 같음이 된 까닭을 결과에 남기지 않아 화면이 그냥 "같음" 이라고만 했다.
### 고친 것
- `FolderComparer` — `SameReason`(None · Style · MergeNotes · StyleAndMergeNotes)을 항목에 남긴다. 설정으로 같음이 된 파일만 한 가지씩 켜서 다시 견줘 까닭을 정한다(그 파일만 값을 치른다).
상태 글자는 `FolderStatusText.Of`(같음 · 같음(스타일만 다름) · 같음(머지 주석만 다름) · 같음(스타일 · 머지 주석만 다름) · 다름 …), 걸러 본 폴더 줄 글자는 `FolderStatusText.FilteredFolder`("같음 N개" · "왼쪽만 N개" · "오른쪽만 N개").
- `FolderViewModel` — 필터가 같은 것만 · 왼쪽에만 · 오른쪽에만이면 가지치기한 뒤 폴더마다 남은 파일 수를 세어 폴더 줄에 적고(`ShowAsFiltered`), 줄 색도 그 갈래로(`DisplayStatus`). 다른 필터는 폴더 자신의 상태 그대로.
- `FolderView.xaml` — 줄 색이 `DisplayStatus` 를 따른다. 상태 칸 폭 90 → 200(긴 글자가 잘리지 않게, 머리글 칸도 같이).
- 하네스 `FolderTest` 15건(77건): 까닭 다섯 경우 · 요약 같음 수 그대로 · 주석 무시를 끄면 주석 파일은 같음 아님 · 글자 다섯 · 폴더 줄 글자 셋.
### 확인한 것 (사용자 설정 그대로, 앱 화면)
| 경우 | 결과 |
|---|---|
| 시험 묶음 "같은 것만" | 폴더 줄 **"같음 122개" · "같음 126개" · "같음 67개" …, 주황 없음** · 파일 줄 모두 "같음" · 요약 `같음 4063` 그대로 (`d10-same-perf-after.png`) |
| 작은 짝 "같은 것만" | `01_같음.cs` 같음 · `04_중괄호만.cs` **같음(스타일만 다름)** · `06_머지주석만.cs` **같음(머지 주석만 다름)** · 요약 `같음 3` 그대로 (`d10-same-small-after.png`) |
- 하네스 22벌 1,146건 통과(+15) · 빌드 경고 0 · 오류 0.
### 알게 된 것 (고치지 않음)
- **BOM · 줄끝 · 인코딩 · 끝 공백 · 빈 줄 · 들여쓰기만 다른 파일도 "주석만 다름"** 이다. 주석 · 공백을 걷어내고 글자로 견주는 판정이라 그렇다(5차 · 3차 설계). 이름이 "주석만" 이라 BOM 만 다른 파일에는 맞지 않는 말이다 — 이름을 바꿀지는 따로 정할 거리.
## F-3. "주석만 다름" 이름을 바꾼다 (2026-09-17, 추가 요청, 완료)
사용자: "이름을 바꿔줘" — F-1 · F-2 를 가리며 적은 "BOM · 줄끝 · 인코딩 · 끝 공백 · 빈 줄 · 들여쓰기만 다른 파일도 '주석만 다름'" 에 대해.
### 까닭
- 이 상태(`CommentOnly`)는 두 파일을 글자로 읽어 **주석과 공백을 걷어낸 코드**가 같은지로 정한다. 글자로 읽으면 BOM · 인코딩 차이가 사라지고, 공백을 지우면 줄끝 · 빈 줄 · 들여쓰기 차이도 사라진다.
F-1 · F-2 의 작은 짝 13개에서 주석이 없는 02 BOM · 03 줄끝 · 07 인코딩 · 08 끝 공백 · 12 빈 줄 · 13 들여쓰기가 모두 "주석만 다름" 이었다 — 판정은 설계대로지만 이름이 사실과 달랐다.
### 고친 것 (판정 · 수는 그대로)
- 이름을 **"다름(코드는 같음)"** 으로 — 이미 있는 "다름(이진)" 과 같은 꼴이라 "다름" 의 한 갈래로 읽힌다. "코드가 다른 것만" 필터와도 짝이 맞는다.
- `FolderStatusText.Of` · 요약(`FolderCompareResult.Summary`) "다름 N(코드는 같음 M)" · 비교 결과 보고서(`CompareReport` 가 같은 글자를 씀) · 범례(설명: "코드는 같고 주석 · 공백 · 빈 줄 · 줄끝 · BOM · 인코딩만 다른 파일입니다") · 코드 설명 주석.
- 웹 문서: 매뉴얼 폴더 비교 상태 설명(F-1 · F-2 표시도 함께 적음) · 발표 · 지금까지 만든 것 · 기획안 구조도 · 시연 · WinMerge 비교의 이름. 지난 기록(3차 연표)은 그때 이름 그대로. 발행은 E-2.
- 하네스 `FolderTest` 1건(78건): 요약이 "(코드는 같음 20)" 이고 "주석만" 이 없다. 글자 검사 기대값도 새 이름으로.
### 확인한 것
- 작은 짝 13개 "전체"(사용자 설정 그대로, `d10-same-rename-all.png`): 02 · 03 · 07 · 08 · 09 · 12 · 13 이 "다름(코드는 같음)", 04 "같음(스타일만 다름)", 06 "같음(머지 주석만 다름)", 05 · 10 · 11 "다름", 01 "같음". 요약 `전체 13개 · 다름 10(코드는 같음 7) · 왼쪽만 0 · 오른쪽만 0 · 같음 3`. 범례 "다름(코드는 같음)".
- 하네스 22벌 1,147건 통과(FolderTest 78 · ReportTest 31) · 빌드 경고 0 · 오류 0.