From 2d3201cda0cda483c4ec7945f387f55ff45b0660 Mon Sep 17 00:00:00 2001 From: ksj09406 Date: Wed, 16 Sep 2026 14:47:23 +0900 Subject: [PATCH] =?UTF-8?q?8=EC=B0=A8=20B-3:=20MERGED=20=EC=B9=B8=20?= =?UTF-8?q?=EC=A4=84=20=EB=B2=88=ED=98=B8=EB=A5=BC=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EB=B2=88=ED=98=B8=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 네 칸 MERGED 칸 번호가 정렬할 때 정해진 채 굳어 있었다. 고른 줄 · 머지 주석으로 결과가 늘어도 다시 매기지 않아 끝 번호가 3363 인데 상태바는 총 3369줄이었다. - 사용자 결정(2026-09-16): 결과 파일 번호로 맞춘다 - 상태바 · [이동] 칸 · 코드 검사와 같은 기준 - MergedNumbering.Assign - 결과에 들어가는 줄만 1부터 센다 - 줄을 만들 때와 요약을 그릴 때마다 다시 매긴다(고르기 · 편집 · 되돌리기 · 주석 끼우기 뒤) - LOCAL (Mine) 칸은 내 파일 번호 그대로 - 하네스 MergeSaveTest 162건(번호 7건), 18벌 928건 통과 확인: MERGED 끝 번호 3363 → 3369, 상태바 총 3369줄 · [이동] 3369 · 저장된 파일 3369줄과 같다. Co-Authored-By: Claude Opus 5 --- doc/history/2026-09-16-8차.md | 45 ++++++++++++++++++++++++ doc/history/changelog.md | 1 + doc/진행상황.md | 2 +- src/MergeHub/Services/MergedNumbering.cs | 42 ++++++++++++++++++++++ src/MergeHub/ViewModels/HomeViewModel.cs | 22 ++++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/MergeHub/Services/MergedNumbering.cs diff --git a/doc/history/2026-09-16-8차.md b/doc/history/2026-09-16-8차.md index 61baf06..9542bf5 100644 --- a/doc/history/2026-09-16-8차.md +++ b/doc/history/2026-09-16-8차.md @@ -157,3 +157,48 @@ cherry-pick 의 BASE 제목에 꼬리가 없는 것은 맞다 — 그때 BASE ### 정하지 않은 것 - git 의 `--allow-empty` 처럼 **빈 cherry-pick 을 커밋으로 남기는 길**은 지시서대로 두지 않았다. 사용자와 정한 뒤에 넣는다. + +## B-3. MERGED 칸 줄 번호가 결과 파일 번호가 아니다 (2026-09-16, 완료) + +**정한 것 (2026-09-16, 사용자)** — 두 가지를 보이고 골랐다. ① 결과 파일 번호로(고름) ② 지금처럼 내 쪽 번호로 두고 그렇다고 적기. +결과 파일 번호는 상태바 · [이동] 칸 · 코드 검사의 "N행" 과 같은 기준이다. + +### 고치기 전에 다시 났다 (새로 만든 저장소, 병합 중 `Motion/Unit0.cs` 를 네 칸으로) + +충돌 6개를 Take Theirs 하면 고른 줄 · 머지 주석으로 결과가 늘어난다. + +| 확인 | 값 | +|---|---| +| 상태바 | **총 3369줄** | +| [이동] 칸에 3369 | 3369행으로 감 | +| **MERGED 칸 끝 번호** | **3363** — 여섯 줄이 모자란다 | +| LOCAL (Mine) 칸 끝 번호 | 3361 (내 파일 그대로 · 맞다) | + +### 원인 + +MERGED 칸 번호는 `MergeLine.LocalNumber` 인데, 이 값은 **정렬기가 짝지을 때 한 번 정해지고 그대로**다. +머지 주석 줄은 새로 끼워 넣으면서 번호를 주지 않았고(`Lines.Insert`), 그 뒤의 줄들도 번호를 다시 매기지 않았다. +그래서 결과가 길어질수록 어긋난다. + +### 고친 것 + +| 파일 | 무엇 | +|---|---| +| `Services/MergedNumbering.cs` (새 파일) | `Assign(결과에 들어가는가[])` — 결과에 들어가는 줄만 1부터 센다. `Count` — 결과 줄 수 | +| `ViewModels/HomeViewModel.cs` | `RenumberMerged(rows)` — 줄 목록에 결과 번호를 다시 매긴다. 두 줄 만들기(두 칸 · 네 칸) 끝과 **요약을 그릴 때마다**(고르기 · 편집 · 되돌리기 · 주석 끼우기 뒤) 부른다 | +| 하네스 `MergeSaveTest` | 번호 검사 7건(결과에 없는 줄 · 끝 번호 = 결과 줄 수 · 빈 목록 · null 등) | + +결과 파일은 `BuildLocalText` 가 `HasLocal` 인 줄만 이어 붙인 것이라, 번호도 같은 기준으로 센다. +LOCAL (Mine) 칸은 `OriginalLocalNumber`(내 파일 번호)를 그대로 쓴다 — 바꾸지 않았다. + +### 확인한 것 (같은 순서로 다시) + +| 확인 | 값 | +|---|---| +| 상태바 | 총 3369줄 | +| **MERGED 칸 끝 번호** | **3369** (3352 ~ 3369) | +| [이동] 칸에 3369 | 3369행 | +| **[Save] 한 뒤 워킹트리 파일** | **3369줄** — 화면 번호와 같다 | +| LOCAL (Mine) 칸 | 3346 ~ 3361 그대로 | + +하네스 18벌 928건 통과(MergeSaveTest 162). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림. diff --git a/doc/history/changelog.md b/doc/history/changelog.md index 733d16e..4642212 100644 --- a/doc/history/changelog.md +++ b/doc/history/changelog.md @@ -8,6 +8,7 @@ | 날짜 | 항목 | 커밋 | |---|---|---| +| 2026-09-16 | **8차 B-3** — 네 칸 MERGED 칸 줄 번호가 정렬할 때 정해진 채 굳어, 고른 줄 · 머지 주석으로 결과가 늘어도 그대로였다(끝 번호 3363 · 상태바 총 3369줄). 사용자가 "결과 파일 번호로" 를 골라, 결과에 들어가는 줄만 1부터 다시 매긴다(MergedNumbering). 줄을 만들 때와 요약을 그릴 때마다 다시 매겨 고르기 · 편집 · 되돌리기 뒤에도 맞는다. 저장된 파일 줄 수(3369)와 화면 번호가 같아짐 | 아래 | | 2026-09-16 | **8차 B-2** — 이미 들어 있는 커밋을 cherry-pick 하면 [커밋] 이 켜지는데 누르면 로그에 "실패: No changes; nothing to commit." 만 남고 진행 줄도 그대로라 같은 단추를 또 누르게 됐다. 커밋할 것이 있는지(HasStagedChanges)를 상태로 들고 있다가 [커밋] 을 끄고, 진행 줄 · 적용 로그가 "가져올(되돌릴) 변경이 없습니다 - [작업 취소] 로 끝냅니다" 라고 말한다. 커밋 직전에도 사람 말로 막는다. 병합 커밋은 트리가 같아도 정상이라 걸지 않음 | 아래 | | 2026-09-16 | **8차 B-1** — rebase · cherry-pick 에서 마지막 충돌을 [Save] 하면 파일 비교 탭이 "남은 차이 6줄" 로 떨어져 충돌 탭과 다른 말을 했다(7차 A-1 이 병합 전용이었고 화면도 MERGE_HEAD 기준으로 물었다). 요약 · BASE 제목을 작업 상태(GitOperationState)에 맞춰 OperationLabels 로 옮김 — 끝말은 충돌 탭 진행 줄과 같은 FinishHint, 차이 줄은 작업별로(받은 · 올린 · 가져온 · 되돌린 변경), 제목 꼬리는 병합 "병합 전 내 쪽" · rebase "올릴 자리" 등. 병합 글은 그대로 | 아래 | | 2026-09-16 | **8차 A-1** — 파일 비교 탭을 처음 여는 것이 [3분할로 열기] 면 고른 파일 대신 첫 충돌 파일이 보였고, 그 화면을 [Save] 하면 **고른 파일에 그 내용이 써졌다**(Unit47 이 Unit15 내용으로 스테이징). 탭을 만들 때의 목록 세우기와 고른 파일 열기가 겹쳐, 늦게 끝난 읽기가 화면을 덮은 것. 읽기는 경로 · 커밋이 바뀌었으면 버리고 한 번 더 읽게, 쓰기(저장 · Save & Commit · 파일 지우기/남기기)는 화면에 실린 파일과 다르면 아무것도 쓰지 않게 했다. 네 길 모두 고른 파일이 열리고 저장이 그 파일에만 감, 병합은 사람 순서 그대로 끝까지(줄끝 0/33 · 내용 검사 0) | 아래 | diff --git a/doc/진행상황.md b/doc/진행상황.md index 8fbcd06..3eed988 100644 --- a/doc/진행상황.md +++ b/doc/진행상황.md @@ -207,7 +207,7 @@ |---|---| | **완료** | B-1 rebase · cherry-pick 에서 마지막 저장 뒤 "남은 차이" 가 뜬다 — 요약 · BASE 제목이 작업(병합 · rebase · cherry-pick · revert)을 따른다. rebase 는 "충돌 정리 끝 · [계속] 으로 rebase 를 이어 갑니다 · 올릴 자리 대비 올린 변경 N줄" · 제목 "올릴 자리". 병합 글은 그대로 | | **완료** | B-2 바뀌는 것 없는 cherry-pick 에서 [커밋] 이 켜지고 누르면 실패한다 — 커밋할 것이 없으면 [커밋] 이 꺼지고 진행 줄 · 로그가 "가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다". 병합 커밋은 그대로(트리가 같아도 정상). `--allow-empty` 는 사용자와 정한 뒤 | -| 대기 | B-3 MERGED 칸 줄 번호가 결과 파일 번호가 아니다 (먼저 사용자와 정함) | +| **완료** | B-3 MERGED 칸 줄 번호가 결과 파일 번호가 아니다 — 사용자가 "결과 파일 번호로" 를 고름(2026-09-16). 결과에 들어가는 줄만 1부터 다시 매긴다. 끝 번호 3363 → 3369 로 상태바 · [이동] 칸 · 저장된 파일(3369줄)과 같아짐 | ### C. 7차에서 남긴 것 diff --git a/src/MergeHub/Services/MergedNumbering.cs b/src/MergeHub/Services/MergedNumbering.cs new file mode 100644 index 0000000..9ec99a0 --- /dev/null +++ b/src/MergeHub/Services/MergedNumbering.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace MergeHub.Services +{ + /// + /// MERGED 칸(네 칸의 결과)에 매길 줄 번호(8차 B-3). + /// + /// 따로 뺀 까닭 - 예전에는 번호를 정렬기가 준 대로 두었다. 줄을 고르거나 머지 주석이 끼어들어 + /// 결과 줄이 늘어도 다시 매기지 않아, MERGED 칸 끝 번호(3363)와 상태바 줄 수(3366)가 어긋났다. + /// 사용자가 결과 파일 번호로 맞추기로 정했다(2026-09-16) - 상태바 · [이동] 칸 · 코드 검사의 "N행" 과 같은 번호다. + /// + /// 결과 파일은 결과에 들어가는 줄만 차례로 이어 붙인 것이다(BASE 에만 있던 줄은 빠진다). + /// 그래서 번호도 그 줄만 1부터 센다. + /// + public static class MergedNumbering + { + /// 행마다 "결과 파일에 들어가는가" 를 받아 번호를 돌려준다. 들어가지 않는 행은 null. + public static int?[] Assign(IReadOnlyList inResult) + { + if (inResult is null) return Array.Empty(); + + var numbers = new int?[inResult.Count]; + var n = 0; + + for (var i = 0; i < inResult.Count; i++) + numbers[i] = inResult[i] ? ++n : (int?)null; + + return numbers; + } + + /// 결과 파일의 줄 수. 상태바가 말하는 "총 N줄" 과 같아야 한다. + public static int Count(IReadOnlyList inResult) + { + if (inResult is null) return 0; + + var n = 0; + foreach (var yes in inResult) if (yes) n++; + return n; + } + } +} diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs index ac567fa..a819f24 100644 --- a/src/MergeHub/ViewModels/HomeViewModel.cs +++ b/src/MergeHub/ViewModels/HomeViewModel.cs @@ -1529,6 +1529,7 @@ namespace MergeHub.ViewModels } RefreshBlockCommentState(rows); + RenumberMerged(rows); // MERGED 칸은 결과 파일 번호로(8차 B-3) return rows; } @@ -1595,6 +1596,7 @@ namespace MergeHub.ViewModels MarkMoves(aligned, rows); RefreshBlockCommentState(rows); + RenumberMerged(rows); // MERGED 칸은 결과 파일 번호로(8차 B-3) return rows; } @@ -3417,6 +3419,9 @@ namespace MergeHub.ViewModels private void UpdateSummaries() { + // 줄을 고르거나 머지 주석이 끼어들면 결과 줄 수가 바뀐다. 그릴 때마다 번호를 다시 매긴다(8차 B-3). + RenumberMerged(Lines); + var total = Lines.Count; var diff = Lines.Count(l => l.IsDifferent); @@ -3756,6 +3761,23 @@ namespace MergeHub.ViewModels SaveResolvedCommand.NotifyCanExecuteChanged(); } + /// + /// MERGED 칸 번호를 결과 파일 번호로 다시 매긴다(8차 B-3). + /// + /// 줄을 고르거나 머지 주석이 끼어들면 결과 줄 수가 바뀐다. 정렬기가 준 번호를 그대로 두면 + /// 끝 번호가 상태바의 "총 N줄" 과 어긋났다. 결과에 들어가는 줄()만 1부터 센다. + /// + private static void RenumberMerged(IList rows) + { + if (rows is null || rows.Count == 0) return; + + var inResult = new bool[rows.Count]; + for (var i = 0; i < rows.Count; i++) inResult[i] = rows[i].HasLocal; + + var numbers = MergedNumbering.Assign(inResult); + for (var i = 0; i < rows.Count; i++) rows[i].LocalNumber = numbers[i]; + } + private string BuildLocalText() { var sb = new StringBuilder();