From c275cf6067862fdd554cb8dd88a701cc7c7d1321 Mon Sep 17 00:00:00 2001 From: ksj09406 Date: Wed, 16 Sep 2026 13:36:00 +0900 Subject: [PATCH] =?UTF-8?q?8=EC=B0=A8=20B-1:=20=EB=A7=88=EC=A7=80=EB=A7=89?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=EB=92=A4=20=EC=9A=94=EC=95=BD=20=C2=B7?= =?UTF-8?q?=20=EC=A0=9C=EB=AA=A9=EC=9D=B4=20=EC=9E=91=EC=97=85=EC=9D=84=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rebase · cherry-pick 에서 마지막 충돌을 [Save] 하면 파일 비교 탭이 "남은 차이 6줄" 로 떨어져 충돌 탭("충돌 정리 끝 - [계속] 으로 rebase 를 이어 갑니다")과 다른 말을 했다. - OperationLabels.ResolvedSummary / BaseHeader 로 옮기고 작업별 글을 붙였다 - MergeSavePlan 의 병합 전용 함수 둘을 걷어냈다 - 화면은 IsMergeInProgress 대신 IsOperationInProgress · OperationState.Kind 를 본다 - 하네스 MergeSaveTest 148건(작업별 16건), 18벌 914건 통과 확인: rebase "충돌 정리 끝 · [계속] 으로 rebase 를 이어 갑니다 · 올릴 자리 대비 올린 변경 6줄" · 제목 "올릴 자리", cherry-pick "… [커밋] 으로 cherry-pick 을 끝냅니다", 병합은 예전 글 그대로. Co-Authored-By: Claude Opus 5 --- doc/history/2026-09-16-8차.md | 42 ++++++++++++++++++++++++ doc/history/changelog.md | 1 + doc/진행상황.md | 2 +- src/MergeHub/Services/MergeSavePlan.cs | 18 ---------- src/MergeHub/Services/OperationLabels.cs | 42 ++++++++++++++++++++++++ src/MergeHub/ViewModels/HomeViewModel.cs | 9 ++--- 6 files changed, 91 insertions(+), 23 deletions(-) diff --git a/doc/history/2026-09-16-8차.md b/doc/history/2026-09-16-8차.md index 2801f3a..2eb0035 100644 --- a/doc/history/2026-09-16-8차.md +++ b/doc/history/2026-09-16-8차.md @@ -70,3 +70,45 @@ - 자동 조작 쪽: Save 직후 찍은 화면이 Git 탭이라 파일 비교 탭 제목이 빈 것으로 읽혔다. 화면은 제대로였다(스크린샷). - 7차 D-1 때 넣은 우회(파일 비교 탭을 먼저 한 번 열기)는 스위치(`D7_NO_PREOPEN`)로 껐다 켤 수 있게 두었다. 8차 E-1 은 끈 채로 한다. + +## B-1. rebase · cherry-pick 에서 마지막 저장 뒤 "남은 차이" 가 뜬다 (2026-09-16, 완료) + +### 고치기 전에 다시 났다 (길마다 저장소를 새로 만들어) + +마지막 한 파일(`Weld/Unit1.cs`)만 남기고 23개를 파일 단위로 풀고, 남은 하나를 네 칸에서 Take Theirs 6번 → [Save]. + +| 길 | 파일 비교 탭 | 충돌 탭 | +|---|---|---| +| rebase | `bbdc66e · Weld/Unit1.cs` · **남은 차이 6줄** | 충돌 정리 끝 - [계속] 으로 rebase 를 이어 갑니다 | +| cherry-pick | `30c2133 · Weld/Unit1.cs` · **남은 차이 6줄** | 충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다 | +| 병합 (회귀) | `c3691b2 · Weld/Unit1.cs · 병합 전 내 쪽` · 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 6줄 | 같은 말 | + +두 화면이 다른 말을 한다. 방금 받아 놓은 6줄이 "아직 할 일" 로 읽힌다 — 7차 A-1 과 같은 증상인데 병합에서만 고쳐져 있었다. + +### 원인 + +7차 A-1 에서 만든 `MergeSavePlan.ResolvedMergeSummary` · `MergeBaseHeader` 가 **병합 전용**이었다. +화면도 `_workspace.IsMergeInProgress`(MERGE_HEAD 기준)로 물었다. rebase 는 MERGE_HEAD 가 없고 cherry-pick 은 `CHERRY_PICK_HEAD` 라 둘 다 "병합 중이 아님" 이 되어 보통 요약("남은 차이 N줄")으로 떨어졌다. +7차 C-2 에서 만든 작업 상태(`GitOperationState` · `OperationLabels`)를 쓰지 않고 있었다. + +### 고친 것 + +| 파일 | 무엇 | +|---|---| +| `Services/OperationLabels.cs` | `ResolvedSummary(작업, 남은 충돌, 차이 줄)` — 끝말은 진행 줄과 같은 `FinishHint`(병합 커밋 · [계속] · [커밋])를 쓴다. 차이 줄은 작업마다 무엇인지 적는다(받은 변경 · 올린 변경 · 가져온 변경 · 되돌린 변경). `BaseHeader(작업, 짧은해시, 경로)` — 병합 "병합 전 내 쪽", rebase **"올릴 자리"**, cherry-pick "가져오기 전 내 쪽", revert "되돌리기 전 내 쪽" | +| `Services/MergeSavePlan.cs` | 병합 전용이던 `ResolvedMergeSummary` · `MergeBaseHeader` 를 걷어냈다(글은 위로 옮김) | +| `ViewModels/HomeViewModel.cs` | 요약 · BASE 제목이 `IsMergeInProgress` 대신 **`IsOperationInProgress` · `OperationState.Kind`** 를 본다 | +| 하네스 `MergeSaveTest` | 병합 글이 예전과 같은지 6건 + 작업별 요약 · 제목 10건 | + +### 확인한 것 (같은 순서로 다시) + +| 길 | 마지막 Save 뒤 파일 비교 탭 | 충돌 탭 | +|---|---|---| +| rebase | **`3e51519 · Weld/Unit1.cs · 올릴 자리`** · **충돌 정리 끝 · [계속] 으로 rebase 를 이어 갑니다 · 올릴 자리 대비 올린 변경 6줄** | 같은 말 | +| cherry-pick | **충돌 정리 끝 · [커밋] 으로 cherry-pick 을 끝냅니다** | 같은 말 | +| 병합 (회귀) | `d091ca2 · Weld/Unit1.cs · 병합 전 내 쪽` · 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 6줄 | 같은 말 | + +cherry-pick 의 BASE 제목에 꼬리가 없는 것은 맞다 — 그때 BASE 는 HEAD 가 아니라 **이력에서 고른 가져올 커밋**이라 +"가져오기 전 내 쪽" 이라고 하면 틀린 말이 된다(제목은 `14a9476 · Weld/Unit1.cs`, HEAD 는 `45bdbf5`). + +하네스 18벌 914건 통과(MergeSaveTest 148). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림. diff --git a/doc/history/changelog.md b/doc/history/changelog.md index eee540b..0d9ffb6 100644 --- a/doc/history/changelog.md +++ b/doc/history/changelog.md @@ -8,6 +8,7 @@ | 날짜 | 항목 | 커밋 | |---|---|---| +| 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) | 아래 | | 2026-09-15 | **8차 지시서** — 7차 전부 끝. D-1 에서 새로 걸린 넷(A-1 고른 파일에 다른 파일 내용이 저장됨 · B-1 rebase / cherry-pick "남은 차이" · B-2 빈 cherry-pick [커밋] · B-3 MERGED 번호)과 7차에서 남긴 것(revert 끝까지 · 원래 작성자 · 창 크기 스냅 등) · 웹 문서 갱신 · 다섯 길 재확인(파일 비교 탭을 미리 열지 않고). 코드 변경 없음 | 아래 | | 2026-09-15 | **7차 D-1** — 병합 · pull · rebase · cherry-pick 을 새 저장소에서 MergeHub 만으로 끝까지(코드 변경 없음). 네 길 모두 커밋까지 · 줄끝 · BOM 바뀐 파일 0 · A-2 · B-1 다시 안 남 · MERGED 줄 번호 안 잘림. 새로 걸린 것: **N1 파일 비교 탭을 처음 여는 것이 [3분할로 열기] 면 다른 파일이 보이고 그대로 [Save] 하면 고른 파일에 그 내용이 써짐** · N2 rebase · cherry-pick 마지막 저장 뒤 "남은 차이"(A-1 이 병합만) · N3 MERGED 번호가 결과 번호가 아님 · N4 빈 cherry-pick [커밋] 이 켜져 실패 → 8차 | 아래 | diff --git a/doc/진행상황.md b/doc/진행상황.md index 8d0fabf..e21f610 100644 --- a/doc/진행상황.md +++ b/doc/진행상황.md @@ -205,7 +205,7 @@ | 상태 | 항목 | |---|---| -| 대기 | B-1 rebase · cherry-pick 에서 마지막 저장 뒤 "남은 차이" 가 뜬다 | +| **완료** | B-1 rebase · cherry-pick 에서 마지막 저장 뒤 "남은 차이" 가 뜬다 — 요약 · BASE 제목이 작업(병합 · rebase · cherry-pick · revert)을 따른다. rebase 는 "충돌 정리 끝 · [계속] 으로 rebase 를 이어 갑니다 · 올릴 자리 대비 올린 변경 N줄" · 제목 "올릴 자리". 병합 글은 그대로 | | 대기 | B-2 바뀌는 것 없는 cherry-pick 에서 [커밋] 이 켜지고 누르면 실패한다 | | 대기 | B-3 MERGED 칸 줄 번호가 결과 파일 번호가 아니다 (먼저 사용자와 정함) | diff --git a/src/MergeHub/Services/MergeSavePlan.cs b/src/MergeHub/Services/MergeSavePlan.cs index 8683b99..2e0271c 100644 --- a/src/MergeHub/Services/MergeSavePlan.cs +++ b/src/MergeHub/Services/MergeSavePlan.cs @@ -50,24 +50,6 @@ namespace MergeHub.Services .Count(); } - /// - /// 병합 중인데 충돌이 다 풀렸을 때 두 칸 비교의 요약. 병합 중이 아니거나 충돌이 남았으면 null(보통 요약을 쓴다). - /// - /// 마지막 충돌을 저장하면 파일 비교 탭은 보통 화면(HEAD ↔ 워킹트리)으로 돌아간다. 거기서 "남은 차이 3줄" 이라고 하면 - /// 방금 받은 줄이 할 일로 읽혀 덜 푼 것처럼 보였다(7차 A-1). 충돌 탭과 같은 말을 하고, 그 줄 수는 무엇인지 적는다. - /// - public static string? ResolvedMergeSummary(bool mergeInProgress, int conflictsLeft, int diffLines) - { - if (!mergeInProgress || conflictsLeft > 0) return null; - - const string done = "충돌 정리 끝 · 병합 커밋을 할 수 있습니다"; - return diffLines <= 0 ? done : $"{done} · 내 쪽 대비 받은 변경 {diffLines}줄"; - } - - /// 병합 중 보통 화면의 BASE 칸 제목. HEAD 는 병합 전 내 쪽이라는 것을 적는다(7차 A-1). - public static string MergeBaseHeader(string shortSha, string path) => $"{shortSha} · {path} · 병합 전 내 쪽"; - - /// /// /// 읽어 온 내용이 지금 화면이 보여야 할 것과 다른가(8차 A-1). /// diff --git a/src/MergeHub/Services/OperationLabels.cs b/src/MergeHub/Services/OperationLabels.cs index b4aaf1b..aed060b 100644 --- a/src/MergeHub/Services/OperationLabels.cs +++ b/src/MergeHub/Services/OperationLabels.cs @@ -85,6 +85,48 @@ namespace MergeHub.Services _ => "병합 커밋을 할 수 있습니다" }; + + /// + /// 충돌을 다 푼 뒤 두 칸 비교(HEAD ↔ 워킹트리)의 요약(7차 A-1 을 작업별로 - 8차 B-1). + /// + /// 마지막 충돌을 저장하면 파일 비교 탭은 보통 화면으로 돌아간다. 거기서 "남은 차이 3줄" 이라고 하면 + /// 방금 받아 놓은 줄이 아직 할 일로 읽혀 덜 푼 것처럼 보인다. 충돌 탭과 같은 말을 하고, + /// 그 줄이 무엇인지 적는다. 진행 중이 아니거나 충돌이 남았으면 null - 그때는 보통 요약이 맞다. + /// + public static string? ResolvedSummary(GitOperationKind kind, int conflictsLeft, int diffLines) + { + if (kind == GitOperationKind.None || conflictsLeft > 0) return null; + + var done = $"충돌 정리 끝 · {FinishHint(kind)}"; + return diffLines <= 0 ? done : $"{done} · {DiffLead(kind)} {diffLines}줄"; + } + + /// 다 푼 뒤 남은 차이가 무엇인지. 작업마다 어느 쪽에서 온 변경인지가 다르다. + private static string DiffLead(GitOperationKind kind) => kind switch + { + GitOperationKind.Rebase => "올릴 자리 대비 올린 변경", + GitOperationKind.CherryPick => "내 쪽 대비 가져온 변경", + GitOperationKind.Revert => "내 쪽 대비 되돌린 변경", + _ => "내 쪽 대비 받은 변경" + }; + + /// + /// 작업이 진행 중일 때 두 칸 비교의 BASE 칸 제목. HEAD 가 무엇인지 적는다(7차 A-1 · 8차 B-1). + /// rebase 중의 HEAD 는 내 쪽이 아니라 올릴 자리다. + /// + public static string BaseHeader(GitOperationKind kind, string shortSha, string path) + { + var lead = kind switch + { + GitOperationKind.Merge => "병합 전 내 쪽", + GitOperationKind.Rebase => "올릴 자리", + GitOperationKind.CherryPick => "가져오기 전 내 쪽", + GitOperationKind.Revert => "되돌리기 전 내 쪽", + _ => string.Empty + }; + + return lead.Length == 0 ? $"{shortSha} · {path}" : $"{shortSha} · {path} · {lead}"; + } /// 충돌 탭의 끝내기 단추 글자. public static string FinishButtonLabel(GitOperationKind kind) => kind switch { diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs index aa3110a..ac567fa 100644 --- a/src/MergeHub/ViewModels/HomeViewModel.cs +++ b/src/MergeHub/ViewModels/HomeViewModel.cs @@ -1385,8 +1385,8 @@ namespace MergeHub.ViewModels ? string.IsNullOrEmpty(baseText) ? $"({baseOrigin}) 이 파일 없음 - 양쪽에서 새로 만든 파일입니다" : $"({baseOrigin}) {path}" - : _workspace.IsMergeInProgress && commit.ShortSha == _workspace.HeadSha - ? MergeSavePlan.MergeBaseHeader(commit.ShortSha, path!) + : _workspace.IsOperationInProgress && commit.ShortSha == _workspace.HeadSha + ? OperationLabels.BaseHeader(_workspace.OperationState.Kind, commit.ShortSha, path!) : $"{commit.ShortSha} · {path}"; LocalHeader = isConflict ? OperationLabels.OursTitle(operation, _workspace.CurrentBranch) @@ -3444,9 +3444,10 @@ namespace MergeHub.ViewModels : incoming == 0 ? $"남은 충돌 {conflicts}개" : $"남은 충돌 {conflicts}개 · 받을 변경 {incoming}줄"; } else if (IsGitMode && - MergeSavePlan.ResolvedMergeSummary(_workspace.IsMergeInProgress, _workspace.Conflicts.Count, diff) is { } resolved) + OperationLabels.ResolvedSummary(_workspace.OperationState.Kind, _workspace.Conflicts.Count, diff) is { } resolved) { - // 병합 중 충돌을 다 푼 뒤의 두 칸(HEAD ↔ 워킹트리). 차이는 할 일이 아니라 방금 받은 변경이다(7차 A-1). + // 작업(병합 · rebase · cherry-pick · revert) 중 충돌을 다 푼 뒤의 두 칸(HEAD ↔ 워킹트리). + // 차이는 할 일이 아니라 방금 받아 놓은 변경이다(7차 A-1 · 8차 B-1). work = resolved; }