diff --git a/doc/history/2026-09-14-7차.md b/doc/history/2026-09-14-7차.md
index b394842..2da73d2 100644
--- a/doc/history/2026-09-14-7차.md
+++ b/doc/history/2026-09-14-7차.md
@@ -2,6 +2,49 @@
지시서: [../작업지시/7차.md](../작업지시/7차.md). 6차 D-1 에서 새로 걸린 세 가지와 6차에서 뺀 pull · rebase · cherry-pick 충돌.
+## A-1. 마지막 충돌을 저장하면 "남은 차이" 가 뜬다 (2026-09-14, 완료)
+
+### 고치기 전에 다시 났다
+
+새로 만든 저장소를 git 으로 병합하고 `Weld/Unit1.cs` 하나만 남긴 채 나머지 25개를 상대 쪽으로 풀었다(준비만 git).
+MergeHub 파일 비교 탭에서 그 파일의 충돌 6개를 Take Theirs → [Save].
+
+| 때 | 칸 제목 | 요약 | 충돌 탭 |
+|---|---|---|---|
+| 충돌 파일 열림 | `(merge base) Weld/Unit1.cs` · 네 칸 | 남은 충돌 6개 | - |
+| **마지막 Save 뒤** (git 충돌 0, 병합 중) | **`90d2a8c · Weld/Unit1.cs`** · 두 칸 | **남은 차이 6줄** | 충돌 정리 끝 - 병합 커밋을 할 수 있습니다 |
+
+두 화면이 다른 말을 한다. 파일 비교 탭만 보면 덜 푼 것으로 읽힌다.
+
+(처음 두 번은 재현 준비가 틀렸다 - 충돌 탭에서 22개를 골라 한 번에 Accept 하려 했는데 자동 조작의 목록 찾기가 엉뚱한 목록을 잡아 한 개만 풀렸고,
+그다음은 준비 스크립트가 모든 충돌을 풀어 버렸다. 세 번째에 저장소를 새로 만들어 git 으로 준비했다.)
+
+### 원인
+
+- [Save] 뒤 `ReloadAfterResolveAsync` → `LoadCommitAsync` 가 충돌이 0 이면 보통 화면(HEAD ↔ 워킹트리)으로 연다. 방금 저장한 파일이 목록에 있어 그대로 골라진다.
+- 보통 화면의 요약은 `남은 차이 N줄`, BASE 제목은 `짧은해시 · 경로` 뿐이라 **병합 중이라는 사정도, 그 차이가 방금 받은 변경이라는 것도** 말하지 않았다.
+
+### 고친 것
+
+| 파일 | 무엇 |
+|---|---|
+| `Services/MergeSavePlan.cs` | `ResolvedMergeSummary(병합 중, 남은 충돌, 차이 줄)` — 병합 중 · 충돌 0 이면 "충돌 정리 끝 · 병합 커밋을 할 수 있습니다", 차이가 있으면 "· 내 쪽 대비 받은 변경 N줄". 아니면 null. `MergeBaseHeader` — `짧은해시 · 경로 · 병합 전 내 쪽` |
+| `ViewModels/HomeViewModel.cs` | `UpdateSummaries`: Git 모드 두 칸에서 위 요약을 쓴다. `LoadFileAsync`: 병합 중이고 BASE 가 HEAD 면 제목에 "병합 전 내 쪽" |
+| 하네스 `MergeSaveTest` | 요약 · 제목 검사 7건(병합 아님 · 충돌 남음 → 보통 요약, 차이 0 · 6 · 음수, "남은" 이 안 들어감) |
+
+화면 틀(두 칸)과 파일 목록은 바꾸지 않았다. 병합 커밋 뒤에는 병합 중이 아니므로 지금처럼 보통 화면이다(6차 B-8).
+
+### 확인한 것 (같은 준비로 다시)
+
+| 때 | 칸 제목 | 요약 · 상태바 |
+|---|---|---|
+| 충돌 파일 열림 | `(merge base) Weld/Unit1.cs` | 남은 충돌 6개 |
+| **마지막 Save 뒤** (git 충돌 0) | **`9ab2256 · Weld/Unit1.cs · 병합 전 내 쪽`** | **충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 6줄** |
+| 충돌 탭 | - | 충돌 정리 끝 - 병합 커밋을 할 수 있습니다 (말이 같다) |
+| [병합 커밋] 뒤 (`cea61d2`, 부모 둘) | `cea61d2 · Weld/Unit1.cs` | 차이 없음 · 병합 진행 중 표시 없음 |
+
+MergeSaveTest 70건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
+
## E-1. [해결로 저장] 이름을 [Save] 로 (2026-09-14, 추가 요청, 완료)
사용자: "해결로 저장은 LOCAL SAVE 버튼이잖아? 그냥 Save 로 이름 바꿔주고".
@@ -26,7 +69,11 @@
| `Io/Unit12.cs` 충돌 1개 Take Theirs → [Save] | 알림 **"Save · Unit12.cs · 남은 충돌 23건"**. git 충돌 24 → 23, 파일 `M ` 스테이징, HEAD 그대로(커밋 없음) |
| 저장 뒤 | 남은 충돌 첫 파일(`Common/Util/Unit15.cs`)이 네 칸으로 열림 |
-하네스는 이 두 파일(`HomeViewModel.cs` · `MergeSavePlan.cs`)을 컴파일하지 않고 글자를 보는 검사도 없어 그대로(22벌 948건). 빌드 경고 0 · 오류 0.
+빌드 경고 0 · 오류 0.
+
+**바로잡음 (A-1 때 발견)** — 처음에 "하네스는 이 파일들을 컴파일하지 않아 그대로" 라고 적었는데 틀렸다.
+`MergeSaveTest` 가 `MergeSavePlan.cs` 를 컴파일하고, 막힘 안내에 "해결로 저장" 이 들어 있는지 보고 있었다.
+찾을 때 하네스 폴더를 빠뜨렸고 하네스를 돌리지 않았다. A-1 에서 기대값을 `[Save]` 로 고치고 "옛 이름이 없다" 검사를 더했다.
설정 파일은 백업 → `CSharpBraceStyle` 끔 → 시험 → 바이트 그대로 되돌림(해시 같음).
(자동 조작 쪽: 앱을 새로 켠 뒤에는 충돌 목록에 고른 것이 없어 [3분할로 열기] 가 아무것도 안 열었다. 목록에서 파일을 고르고 다시 했다.)
diff --git a/doc/history/changelog.md b/doc/history/changelog.md
index df7ee12..1e97957 100644
--- a/doc/history/changelog.md
+++ b/doc/history/changelog.md
@@ -8,6 +8,7 @@
| 날짜 | 항목 | 커밋 |
|---|---|---|
+| 2026-09-14 | **7차 A-1** — 마지막 충돌을 [Save] 하면 파일 비교 탭이 "남은 차이 6줄" 로 떨어져 덜 푼 것처럼 보이던 것. 병합 중 충돌 0 이면 두 칸 요약이 "충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 N줄", BASE 제목에 "병합 전 내 쪽". E-1 때 못 돌린 MergeSaveTest 기대값도 [Save] 로 | 아래 |
| 2026-09-14 | **7차 지시서 · E-1** — 6차 D-1 에서 걸린 세 가지와 pull · rebase · cherry-pick 충돌로 7차 지시서를 씀. 병합 중 [해결로 저장] 단추를 [Save] 로(LOCAL 저장 단추라 Save & Commit 과 짝). 하는 일 그대로, 알림 · 막힘 안내 · 웹 문서 이름도 | 아래 |
| 2026-09-14 | **6차 D-1** — 새로 만든 저장소를 MergeHub 만으로 처음부터 병합 커밋까지(충돌 26 · 자동 2 · 파일 단위 15 · 3분할 7 · 지우기/남기기 2). 줄끝 · BOM 이 바뀐 파일 0/33, 표식 0. 5차 C-1 의 23가지 중 사라짐 18. 새로 걸린 3가지는 7차로. 코드 변경 없음 | 아래 |
| 2026-09-14 | **6차 C-1** — 병합 · revert · cherry-pick · rebase · pull 결과가 로그에 두 번 찍히던 것을 한 번으로. 충돌 탭 목록에 종류(양쪽 수정 · 상대 삭제 · 내가 삭제 · 양쪽 새 파일)와 "남은 충돌 N개 · 푼 것 M개 (M/전체)". 처음 충돌 목록을 .git 에 적어 두어 앱을 다시 켜도 이어짐 | 아래 |
diff --git a/doc/진행상황.md b/doc/진행상황.md
index fdb0bb5..c80b880 100644
--- a/doc/진행상황.md
+++ b/doc/진행상황.md
@@ -150,7 +150,7 @@
| 상태 | 항목 |
|---|---|
-| 대기 | A-1 마지막 충돌을 저장하면 "남은 차이" 가 뜬다 |
+| **완료** | A-1 마지막 충돌을 저장하면 "남은 차이" 가 뜬다 — 병합 중 충돌 0 이면 "충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 N줄", 제목에 "병합 전 내 쪽" |
| 대기 | A-2 3분할에서 줄을 골라도 로그는 "3-Way 안 씀" 이라고 한다 |
### B. 치우기
diff --git a/src/MergeHub/Services/MergeSavePlan.cs b/src/MergeHub/Services/MergeSavePlan.cs
index 1ae7591..e69618a 100644
--- a/src/MergeHub/Services/MergeSavePlan.cs
+++ b/src/MergeHub/Services/MergeSavePlan.cs
@@ -50,6 +50,23 @@ 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} · 병합 전 내 쪽";
+
///
/// git 은 경로를 '/' 로, 대소문자를 그대로 본다. 윈도우 경로 구분자로 들어와도 같게 맞춘다.
/// 대소문자는 맞추지 않는다 - git 이 서로 다른 파일로 볼 수 있다.
diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs
index f972e6c..d1ee5c3 100644
--- a/src/MergeHub/ViewModels/HomeViewModel.cs
+++ b/src/MergeHub/ViewModels/HomeViewModel.cs
@@ -1304,7 +1304,9 @@ namespace MergeHub.ViewModels
? string.IsNullOrEmpty(baseText)
? $"({baseOrigin}) 이 파일 없음 - 양쪽에서 새로 만든 파일입니다"
: $"({baseOrigin}) {path}"
- : $"{commit.ShortSha} · {path}";
+ : _workspace.IsMergeInProgress && commit.ShortSha == _workspace.HeadSha
+ ? MergeSavePlan.MergeBaseHeader(commit.ShortSha, path!)
+ : $"{commit.ShortSha} · {path}";
LocalHeader = _workspace.CurrentBranch;
RemoteHeader = isConflict
? $"REMOTE · {theirsName ?? "THEIRS"}"
@@ -3321,6 +3323,12 @@ namespace MergeHub.ViewModels
? "충돌 정리 끝"
: incoming == 0 ? $"남은 충돌 {conflicts}개" : $"남은 충돌 {conflicts}개 · 받을 변경 {incoming}줄";
}
+ else if (IsGitMode &&
+ MergeSavePlan.ResolvedMergeSummary(_workspace.IsMergeInProgress, _workspace.Conflicts.Count, diff) is { } resolved)
+ {
+ // 병합 중 충돌을 다 푼 뒤의 두 칸(HEAD ↔ 워킹트리). 차이는 할 일이 아니라 방금 받은 변경이다(7차 A-1).
+ work = resolved;
+ }
EditSummary = _undo.Count == 0 && _redo.Count == 0
? work