Ubisam-MergeTool/doc/history/2026-09-17-10차.md
ksj09406 035b3e9d26 10차 D-1 기록: 첫 폴더 비교 9.2초는 캐시를 비워도 다시 안 남 - 고치지 않음
파일마다 버퍼 없이(FILE_FLAG_NO_BUFFERING) 열었다 닫아 캐시를 비운 뒤 쟀다
(한 갈래 읽기 0.4 → 1.8초로 먹는 것 확인).

- 4,500개 묶음 전체 비교: 데운 상태 479ms, 캐시 비운 뒤 535 · 455 · 494ms (여러 갈래 읽기)
- 크기 같은 4,063쌍 읽기: 갈래 1 1,775ms · 4 583 · 16 318 · 32 305 · 64 332
- 앱을 캐시 비우고 새로 켠 첫 [비교]도 1.0~1.8초(누름 대기 포함) - 둘째와 같음
- 9.2초는 다시 안 남(디스크 정보 캐시 · 백신 짐작) - 제품 코드 변경 없음
- 웹 문서 "알아 둘 한계" 를 잰 값으로 고침(발행은 E-2)
- NVMe SSD 에서만 잼, HDD 는 재 보지 않음

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

18 KiB

10차 진행 기록 (2026-09-17 ~)

지시서: ../작업지시/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 를 그대로 컴파일, 앱 코드 변경 없음) · 앱에서는 비운 뒤 새로 켜서 비교.
  • 백신 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 라면 베타 배포 때 재 볼 거리다.