From 69d3fa6915b3ed1ae201af9894046d621ae56333 Mon Sep 17 00:00:00 2001 From: ksj09406 Date: Mon, 14 Sep 2026 14:33:17 +0900 Subject: [PATCH] =?UTF-8?q?6=EC=B0=A8=20B-7:=20=EB=B3=91=ED=95=A9=20?= =?UTF-8?q?=EC=A4=91=20=EC=83=81=ED=83=9C=EB=B0=94=EB=A5=BC=20=EB=82=B4=20?= =?UTF-8?q?=EC=AA=BD=20=ED=8C=8C=EC=9D=BC=20=EA=B8=B0=EC=A4=80=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C,=20=EC=9A=94=EC=95=BD=EC=97=90=20=EB=82=A8=EC=9D=80?= =?UTF-8?q?=20=EC=B6=A9=EB=8F=8C=20=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 --- doc/history/2026-09-14-6차.md | 52 ++++++++++++++++++++++++ doc/history/changelog.md | 1 + doc/web/index.html | 13 +++--- doc/진행상황.md | 2 +- src/MergeHub/Services/GitService.cs | 21 ++++++++++ src/MergeHub/Services/IGitService.cs | 3 ++ src/MergeHub/ViewModels/HomeViewModel.cs | 30 +++++++++++--- 7 files changed, 110 insertions(+), 12 deletions(-) diff --git a/doc/history/2026-09-14-6차.md b/doc/history/2026-09-14-6차.md index d329e29..d0303c4 100644 --- a/doc/history/2026-09-14-6차.md +++ b/doc/history/2026-09-14-6차.md @@ -745,3 +745,55 @@ Allman 은 모두 새 줄(Visual Studio 기본값과 같다). 처음에는 Defau 시연 저장소를 git 으로 병합하면 충돌 8개(같은 줄 · 머지 주석 줄 위 · 줄 끝 · 스타일 · 양쪽 새 파일 · 한쪽 삭제 · CP949 · XAML), `Gripper.cs` · `Heater.cs` 는 자동 병합. MergeHub 로 병합하면 머지 주석만 다른 2개를 스스로 풀어 6개. 처음 만든 생성기는 CP949 파일을 UTF-8 로 읽어 충돌이 안 났고, `Gripper.cs` 는 맞붙은 줄을 고쳐 충돌이 났다. 둘 다 고쳐 다시 만들었다. `make-demo.ps1` 은 PowerShell 5.1 이 한글을 읽도록 BOM 을 붙였다. + +## B-7. 상태바가 병합 중에 믿을 수 없는 값을 보인다 (2026-09-14, 완료) + +### 고치기 전에 다시 났다 + +새로 만든 저장소(충돌 23)를 병합하고 파일 비교 탭에서 충돌 파일을 열었다. + +| 파일 | git 내 쪽(ours) 원본 | 상태바 인코딩 · 줄바꿈 | +|---|---|---| +| `Ui/Views/NewPanel.cs` (양쪽 새 파일) | BOM · CRLF 2/2줄 | **UTF-8 · 혼합** | +| `Io/LineEnding.cs` | BOM · CRLF 60/60줄 | **UTF-8 · 혼합** | +| `Io/Unit12.cs` | BOM · CRLF | UTF-8 (BOM) · CRLF (충돌 표시 줄이 CRLF 라 우연히 맞음) | + +워킹트리 파일에는 git 이 넣은 충돌 표시 때문에 `NewPanel.cs` 에 홀로 LF 3개, `LineEnding.cs` 에 63개가 섞였고 BOM 도 안 보였다. + +`Io/Unit12.cs` 에서 Take Theirs 로 충돌을 정하자 오른쪽 칸은 "충돌 정리 끝" 인데 상태바는 **"남은 차이 1줄"** 그대로. 남은 충돌 수는 상태바 어디에도 없었다. + +### 무엇이 원인이었나 + +- 파일 비교 탭이 충돌 파일도 워킹트리(`DescribeWorkingFile`)로 인코딩 · 줄바꿈을 읽었다. 저장(해결로 저장)은 내 쪽 파일 형식을 따르는데(A-1) 상태바만 다른 것을 봤다. +- 상태바 요약은 "BASE 와 다른 줄 수" 였다. 네 칸에서는 정한 충돌도 BASE 와 달라 줄지 않는다. +- 확인하다 하나 더: 요약을 만든 **뒤에** 범례 수(남은 충돌 수 포함)를 셌다. 새 요약에 남은 충돌 수를 넣자 한 박자 늦어, 여섯 개를 다 정해도 "남은 충돌 1개" 로 남았다. + +### 고친 것 + +| 파일 | 무엇 | +|---|---| +| `Services/GitService.cs` · `IGitService.cs` | `DescribeConflictFile` — 인덱스의 내 쪽(ours) blob, 없으면 상대 쪽 · 공통 조상 blob 으로 판별. 충돌이 아니면 워킹트리 | +| `ViewModels/HomeViewModel.cs` (`LoadFileAsync`) | 충돌 파일이면 `DescribeConflictFile` | +| `ViewModels/HomeViewModel.cs` (`UpdateSummaries`) | 네 칸이면 **"남은 충돌 N개 · 받을 변경 M줄"**(정한 충돌 · 이미 받은 줄 · 무시한 줄은 세지 않음), 둘 다 0 이면 "충돌 정리 끝". 두 칸은 "남은 차이 N줄"(0 이면 "차이 없음"). 범례 수를 요약보다 **먼저** 센다 | + +### 확인한 것 (새로 만든 저장소, C# 스타일 맞춤은 확인 동안만 끔 - 설정 파일은 원래 바이트로 되돌림) + +| 파일 | 상태바 | git 내 쪽 원본 | +|---|---|---| +| `Ui/Views/NewPanel.cs` | 남은 충돌 2개 · **UTF-8 (BOM) · CRLF** | BOM · CRLF 2/2 | +| `Io/LineEnding.cs` | 남은 충돌 1개 · **UTF-8 (BOM) · CRLF** | BOM · CRLF 60/60 | +| `Common/Util/한글설명.cs` | 남은 충돌 1개 · **CP949 · CRLF** | BOM 없음 · UTF-8 아님 · CRLF 10/10 | +| `Motion/Unit0.cs` | 남은 충돌 6개 · UTF-8 (BOM) · CRLF | BOM · CRLF 3,363/3,363 | + +`Motion/Unit0.cs` 충돌 여섯 개를 Take Theirs 로 하나씩 정하며 읽었다. + +| 정한 수 | 상태바 요약 | 오른쪽 칸 | +|---|---|---| +| 0 | 남은 충돌 6개 | 남은 충돌 6개 | +| 1 ~ 5 | 남은 충돌 5 · 4 · 3 · 2 · 1개 · 편집 N건 | 같음 | +| 6 | **충돌 정리 끝** · 편집 6건 | 충돌 정리 끝 | +| Undo 한 번 | 남은 충돌 1개 · 편집 5건 · 되돌리기 1건 | 남은 충돌 1개 | + +(자동 조작은 파일 콤보 항목이 화면에 보이는 것만 만들어져 처음에 두 파일을 못 골랐다. 항목을 이름으로 불러와 고르게 고쳐 다시 쟀다.) + +빌드 경고 0 · 오류 0. diff --git a/doc/history/changelog.md b/doc/history/changelog.md index 888e457..c555edb 100644 --- a/doc/history/changelog.md +++ b/doc/history/changelog.md @@ -8,6 +8,7 @@ | 날짜 | 항목 | 커밋 | |---|---|---| +| 2026-09-14 | **6차 B-7** — 병합 중 상태바 인코딩 · 줄바꿈을 충돌 표시가 든 워킹트리가 아니라 내 쪽(ours) 파일로("UTF-8 · 혼합" → "UTF-8 (BOM) · CRLF"). 네 칸 요약을 "남은 충돌 N개 · 받을 변경 M줄" 로, 범례 수를 먼저 세어 한 박자 늦던 것도 고침 | 아래 | | 2026-09-14 | **E-1 C# 코드 스타일 맞춤** — AURORA(형식 · 메서드만 새 줄, `} else {`) / Allman(모두 새 줄)로 중괄호 줄바꿈을 맞춘 뒤 비교. 두 칸 · 네 칸 · mergetool · 폴더 비교, 설정. 스타일만 바뀐 편집은 파일을 바꿀 때 묻지 않음. StyleTest 78건 | 아래 | | 2026-09-14 | **E-2 시연 재료** — `demo\make-demo.ps1` · `tools\DemoMaker`. 지어낸 코드로 폴더 비교 · 스타일 · mergetool · 큰 파일 · 병합 저장소(`D:\MergeHubDemo\repo`) | 아래 | | 2026-09-14 | **6차 B-6** — 충돌 탭에서 여러 파일을 골라(Ctrl · Shift) Accept 를 한 번에. 작업 하나로 풀고 저장소 다시 읽기는 끝에 한 번. 같은 줄 충돌 15개 22.0초 → 1.2초 | 아래 | diff --git a/doc/web/index.html b/doc/web/index.html index a3424c3..423704c 100644 --- a/doc/web/index.html +++ b/doc/web/index.html @@ -257,7 +257,7 @@ figcaption{font-size:.82rem;color:var(--ink-3);margin-top:6px}
22벌 · 948건검사 하네스 전부 통과
-
11 / 156차 항목 완료 (B-7 · B-8 · C-1 · D-1 남음)
+
12 / 156차 항목 완료 (B-8 · C-1 · D-1 남음)
68MergeHub 로컬 커밋 (푸시 0)
26 → 24만든 저장소 병합 충돌 (주석만 다른 2건 자동 해결)
@@ -841,7 +841,7 @@ Log("step 5");
  • 완료 B-6 충돌 여러 개 한 번에 · C# 스타일 맞춤 · 시연 재료
  • -
  • 대기 B-7 병합 중 상태바 값
  • +
  • 완료 B-7 병합 중 상태바 값 — 내 쪽 파일 기준 · 남은 충돌 수
  • 대기 B-8 병합 커밋 뒤 탭 상태
  • 대기 C-1 로그 · 목록 다듬기
@@ -878,14 +878,14 @@ Log("step 5");
앞으로 남은 내용

남은 일

-

6차 지시서의 남은 네 항목과 일부러 미뤄 둔 것. 6차 규칙대로 B → C → D 순서로 간다.

+

6차 지시서의 남은 세 항목과 일부러 미뤄 둔 것. 6차 규칙대로 B → C → D 순서로 간다.

6차 — 병합을 끝까지 믿고 쓸 수 있게

-

15개 항목 중 A 다섯 · B-1 ~ B-6 이 끝났다(B-6: 같은 줄 충돌 15개 22.0초 → 1.2초). 남은 것은 아래 순서다.

+

15개 항목 중 A 다섯 · B-1 ~ B-7 이 끝났다(B-6: 같은 줄 충돌 15개 22.0초 → 1.2초 · B-7: 병합 중 상태바가 내 쪽 파일 기준, 남은 충돌 수). 남은 것은 아래 순서다.

- + @@ -970,6 +970,7 @@ Log("step 5"); +
항목상태무엇이 문제인가끝났다고 볼 기준
B-7 상태바가 병합 중에 믿을 수 없는 값을 보인다대기인코딩 · 줄바꿈을 충돌 표시가 들어간 워킹트리 파일에서 읽어, 양쪽 CRLF 인 파일도 “UTF-8 · 혼합”. “남은 차이 6줄” 이 충돌을 다 정해도 그대로.병합 중 상태바 인코딩 · 줄바꿈이 ours 기준. 상태바에 남은 충돌 수가 나오고 풀면 준다.
B-7 상태바가 병합 중에 믿을 수 없는 값을 보인다완료인코딩 · 줄바꿈을 충돌 표시가 들어간 워킹트리 파일에서 읽어, 양쪽 CRLF 인 파일도 “UTF-8 · 혼합”. “남은 차이 6줄” 이 충돌을 다 정해도 그대로.병합 중 상태바 인코딩 · 줄바꿈이 ours 기준. 상태바에 남은 충돌 수가 나오고 풀면 준다.
B-8 병합 커밋 뒤 파일 비교 탭이 어정쩡하게 남는다대기목록이 비고, 병합과 상관없는 파일이 BASE 칸에만 뜨고 언어는 “평문”.병합 커밋이 끝나면 병합 전과 같은 보통 상태(선택 커밋 = 방금 만든 병합 커밋).
C-1 로그와 목록 다듬기대기“충돌 22건” 로그가 두 번. 충돌 종류 표시가 들쭉날쭉(상대쪽 삭제만). 풀린 개수 없음. 로그가 CP949 를 “ks_c_5601-1987” 로 적음.로그 한 번. 종류(양쪽 수정 · 상대 삭제 · 내가 삭제 · 양쪽 새 파일)와 풀린 개수. 인코딩 이름이 상태바와 같음.
D-1 병합을 처음부터 다시 끝까지대기A ~ C 를 고친 뒤 시험 저장소(C1Repo)를 새로 만들어 같은 병합을 다시 한다. 5차 C-1 과 같은 표로 23가지 중 무엇이 사라졌는지 적는다.MergeHub 만으로 병합 커밋까지. 커밋된 파일 중 줄끝이 바탕과 달라진 파일 0개. A 다섯 가지가 다시 나지 않는다. 새로 걸린 것은 고치지 말고 적어 7차로.
B-4 발견 ②git mergetool 세 벌을 두 칸이 아니라 네 칸으로 열고 MERGED 에 씀저장 뒤 BOM · CRLF 42 · 홀로 LF 0 · ArgsTest 36건
B-5머지 주석을 비교에서 무시(두 칸 · 네 칸 · 폴더), 주석만 다른 git 충돌 자동 해결, 설정에서 끔git 충돌 26 → 24 · 두 칸 남은 차이 2 → 0 · NoteTest 29 → 64
B-6충돌 탭에서 여러 파일을 골라 Accept 한 번, 저장소 다시 읽기는 끝에 한 번같은 줄 충돌 15개 22.0초 → 1.2초
B-7병합 중 상태바 인코딩 · 줄바꿈을 내 쪽(ours) 파일로, 요약에 "남은 충돌 N개 · 받을 변경 M줄"“UTF-8 · 혼합” → “UTF-8 (BOM) · CRLF” · 충돌 6개 정하며 6 → 0
E-1C# 코드 스타일 맞춤(AURORA / Allman) — 두 칸 · 네 칸 · mergetool · 폴더 비교 · 설정시연 파일 남은 차이 39줄 → 1줄 · StyleTest 78건
E-2시연 재료 demo\make-demo.ps1 — 폴더 비교 · 스타일 · mergetool · 큰 파일 · 병합 저장소시연 저장소 git 충돌 8 → MergeHub 6
@@ -1125,7 +1126,7 @@ Log("step 5"); 단계v1.1 계획실제상태 1 착수 · 설계09.02 – 09.04 · 요구사항 · 구조 · WPF 골격기획안 v1.1(09-03). 구조를 App · Core · Git · UI 분리 대신 UbisamBase 셸 + 플러그인으로완료 2 기반 구축09.07 – 09.14 · Git 연동 · 커밋 그래프 · 편집기 · 비교 엔진09-07 방향 전환 · 09-08 기능 덩어리 5개 · 09-09 3차 · 09-10 4차 · 09-11 5차. MVP 8개가 이 단계 안에 모두 들어갔다완료 - 3 핵심 기능09.15 – 09.23 · 3-Way · 부분 수용 · Undo · 우클릭 · Git 메뉴기능은 앞당겨 끝났으므로 “병합을 끝까지 믿고 쓸 수 있게”(6차)로 쓴다. 09-14: A 5 · B 6 완료, B-7 · B-8 · C-1 · D-1 남음진행 + 3 핵심 기능09.15 – 09.23 · 3-Way · 부분 수용 · Undo · 우클릭 · Git 메뉴기능은 앞당겨 끝났으므로 “병합을 끝까지 믿고 쓸 수 있게”(6차)로 쓴다. 09-14: A 5 · B 7 완료, B-8 · C-1 · D-1 남음진행 4 테스트 · 배포09.29 – 10.02 · 성능 · 인코딩/줄바꿈 검증 · 베타 · 매뉴얼성능 · 인코딩 · 줄바꿈 검증은 5차 · 6차에서 앞당겨 함. 매뉴얼 초안은 이 문서. 베타 배포는 대기대기

일하는 방식 — v1.1 에 없던 것

diff --git a/doc/진행상황.md b/doc/진행상황.md index ab3381b..39c956e 100644 --- a/doc/진행상황.md +++ b/doc/진행상황.md @@ -110,7 +110,7 @@ | **완료** | B-4 확인 중 발견 두 건 — 멀리 건너뛰면 네 칸이 위로 밀려 아래가 빔 · `git mergetool` 세 벌이 두 칸으로 열림 | | **완료** | B-5 머지 주석은 소스에 넣고, 병합 뒤에는 그 줄을 무시한다 — 비교(두 칸 · 네 칸 · 폴더)에서 가리고, 주석만 다른 git 충돌은 양쪽 주석을 남겨 자동으로 푼다. 설정에서 끔 | | **완료** | B-6 충돌 탭에서 하나씩 누를 때마다 오래 기다린다 — 여러 개 골라 Accept 한 번, 다시 읽기는 끝에 한 번. 15개 22.0초 → 1.2초 | -| 대기 | B-7 상태바가 병합 중에 믿을 수 없는 값을 보인다 | +| **완료** | B-7 상태바가 병합 중에 믿을 수 없는 값을 보인다 — 인코딩 · 줄바꿈을 내 쪽(ours) 파일로, 요약에 "남은 충돌 N개 · 받을 변경 M줄" | | 대기 | B-8 병합 커밋 뒤 파일 비교 탭이 어정쩡하게 남는다 | ### E. 추가 요청 (2026-09-14) diff --git a/src/MergeHub/Services/GitService.cs b/src/MergeHub/Services/GitService.cs index 7eedff4..6de166c 100644 --- a/src/MergeHub/Services/GitService.cs +++ b/src/MergeHub/Services/GitService.cs @@ -1654,6 +1654,27 @@ namespace MergeHub.Services /// 워킹트리 파일의 인코딩과 줄바꿈 방식을 사람이 읽을 형태로 알려준다. /// 편집 화면 상태바에 띄워, 저장할 때 무엇이 유지되는지 사용자가 알 수 있게 한다. /// + /// + /// 병합 중 충돌 파일의 인코딩과 줄바꿈 - 내 쪽(ours) 파일 기준(6차 B-7). + /// + /// 워킹트리 파일에는 git 이 충돌 표시를 LF 로 넣어 두어서, 양쪽 다 CRLF 인 파일도 "혼합" 으로 읽혔다. + /// 저장(해결로 저장)도 내 쪽 파일의 형식을 따르므로(6차 A-1) 상태바가 같은 것을 보여야 한다. + /// 내 쪽이 없으면(내가 지운 파일) 상대 쪽, 그것도 없으면 공통 조상. 충돌이 아니면 워킹트리 파일을 본다. + /// + public TextFileInfo DescribeConflictFile(string path) + { + var normalized = NormalizePath(path); + var conflict = Repo.Index.Conflicts[normalized]; + var blob = conflict is null + ? null + : LookupBlob(conflict.Ours) ?? LookupBlob(conflict.Theirs) ?? LookupBlob(conflict.Ancestor); + + if (blob is null) return DescribeWorkingFile(path); + + var bytes = ReadBlobBytes(blob, normalized); + return new TextFileInfo(DescribeEncoding(bytes), DescribeNewLine(DecodeText(bytes))); + } + public TextFileInfo DescribeWorkingFile(string path) { var full = ToFullPath(path); diff --git a/src/MergeHub/Services/IGitService.cs b/src/MergeHub/Services/IGitService.cs index f819fbf..7ecc0cd 100644 --- a/src/MergeHub/Services/IGitService.cs +++ b/src/MergeHub/Services/IGitService.cs @@ -97,6 +97,9 @@ namespace MergeHub.Services /// 워킹트리 파일의 인코딩·줄바꿈 방식(상태바 표시용). TextFileInfo DescribeWorkingFile(string path); + /// 병합 중 충돌 파일의 인코딩·줄바꿈. 내 쪽(ours) 파일 기준(6차 B-7). + TextFileInfo DescribeConflictFile(string path); + /// 편집기에서 직접 수정한 본문으로 해결. /// /// 충돌 파일을 이 글로 풀고 스테이징한다. 저장 형식이 "원본 유지"(또는 null)면 내 쪽(ours) 파일의 diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs index 09abf59..7d4f62d 100644 --- a/src/MergeHub/ViewModels/HomeViewModel.cs +++ b/src/MergeHub/ViewModels/HomeViewModel.cs @@ -1322,7 +1322,10 @@ namespace MergeHub.ViewModels _originalLocalText = BuildLocalText(); SyncEditorFromLines(); - var info = _workspace.Git.DescribeWorkingFile(path!); + // 충돌 파일은 충돌 표시가 든 워킹트리가 아니라 내 쪽 파일로 본다 - 저장도 그 형식을 따른다(6차 B-7). + var info = isConflict + ? _workspace.Git.DescribeConflictFile(path!) + : _workspace.Git.DescribeWorkingFile(path!); RefreshLanguage(); FileEncoding = info.Encoding; FileNewLine = info.NewLine; @@ -3301,11 +3304,28 @@ namespace MergeHub.ViewModels DiffSummary = total == 0 ? "-" : $"총 {total}줄"; DiffVersion++; - EditSummary = _undo.Count == 0 && _redo.Count == 0 - ? $"남은 차이 {diff}줄" - : $"남은 차이 {diff}줄 · 편집 {_undo.Count}건 · 되돌리기 {_redo.Count}건"; - + // 범례 수(남은 충돌 수 포함)를 먼저 센다. 아래 요약이 그 수를 쓴다 - 뒤에서 세면 + // 상태바가 한 박자 늦어, 충돌을 다 정해도 "남은 충돌 1개" 로 남았다(6차 B-7 확인 중). UpdateLegendCounts(); + + // 네 칸에서는 "남은 일" 이 차이 줄 수가 아니다(6차 B-7). 정한 충돌도 BASE 와는 여전히 달라 + // "남은 차이 1줄" 이 끝까지 남았고, 남은 충돌은 오른쪽 칸에만 있었다. + // 사람이 할 일 두 가지만 센다 - 아직 안 정한 충돌, 아직 안 받은 상대 쪽 변경. + var work = diff == 0 ? "차이 없음" : $"남은 차이 {diff}줄"; + if (IsThreeWay) + { + var conflicts = UnresolvedConflictCount; + var incoming = Lines.Count(l => l.ThreeWay == ThreeWayState.RemoteChanged && l.CanTakeRemote && + !l.IsApplied && !l.IsManuallyEdited && !l.IsIgnored); + work = conflicts == 0 && incoming == 0 + ? "충돌 정리 끝" + : incoming == 0 ? $"남은 충돌 {conflicts}개" : $"남은 충돌 {conflicts}개 · 받을 변경 {incoming}줄"; + } + + EditSummary = _undo.Count == 0 && _redo.Count == 0 + ? work + : $"{work} · 편집 {_undo.Count}건 · 되돌리기 {_redo.Count}건"; + RefreshProblems(); }