diff --git a/doc/history/2026-09-14-7차.md b/doc/history/2026-09-14-7차.md
index a4f92ac..22e4bbf 100644
--- a/doc/history/2026-09-14-7차.md
+++ b/doc/history/2026-09-14-7차.md
@@ -45,6 +45,47 @@ MergeHub 파일 비교 탭에서 그 파일의 충돌 6개를 Take Theirs → [S
MergeSaveTest 70건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
+## A-2. 3분할에서 줄을 골라도 로그는 "3-Way 안 씀" 이라고 한다 (2026-09-14, 완료)
+
+### 고치기 전에 다시 났다
+
+새로 만든 저장소를 git 으로 병합(충돌 26)하고 MergeHub 로 열었다. 파일 비교 탭이 첫 충돌 파일 `Common/Util/Unit15.cs` 를 네 칸으로 연다.
+
+| 확인 | 결과 |
+|---|---|
+| 칸 | 네 칸 · REMOTE 제목 `REMOTE · feature/theirs` |
+| 머리의 3-Way 콤보 | **`(3-Way 안 씀)`** — 네 칸이 떠 있는데 콤보는 안 쓴다고 말한다 |
+| [다음 충돌] → Take Theirs | 로그 **`10행 (3-Way 안 씀) 반영`** |
+| Undo → Take Mine | 로그 **없음** — 무엇을 골랐는지 남지 않는다 |
+
+### 원인
+
+- `ApplyRemote` 가 로그에 3-Way 콤보 값(`RemoteBranch`)을 썼다. 충돌 파일은 콤보를 안 건드리고 네 칸을 띄우므로(6차 A-3) 그 값이 `(3-Way 안 씀)` 이다.
+- `TakeLocalLine` 은 줄이 이미 내 것과 같으면 표시만 남기고 로그 없이 돌아갔다. 충돌에서 Take Mine 은 대개 이 경우다.
+- 콤보는 병합 충돌에서 가리킬 것이 없는데도 그대로 보였다.
+
+### 고친 것
+
+| 파일 | 무엇 |
+|---|---|
+| `Services/MergeNames.cs` | `SideLabel` · `TakeTheirsLog` · `TakeMineLog`. 병합의 두 쪽이면 `Theirs(이름)` · `Mine(이름)`, 이미 내 것이면 "으로 정함". 콤보로 고른 브랜치 3-Way 는 지금 문구 그대로("7행 develop 반영", "5행 내 원본으로 되돌림") |
+| `ViewModels/HomeViewModel.cs` | 충돌 파일을 열 때 상대 이름(`GetMergeTheirsName`)을, git mergetool 세 벌은 파일 이름을 들고 있는다. Take Theirs · Take Mine 로그가 위 함수를 쓴다. Take Mine 이 내용을 안 바꿔도 병합의 두 쪽이면 로그를 남긴다. `IsConflictThreeWay` · `ShowBranchCombo` · `ConflictSideText` |
+| `Views/HomeView.xaml` | 충돌 네 칸이면 3-Way 콤보를 감추고 그 자리에 **"병합 충돌 · REMOTE = 상대 이름"** |
+| 하네스 `MergeSaveTest` | 로그 검사 12건(충돌 Theirs · 삭제 · 이름 모름, 브랜치 3-Way 그대로, Mine 정함 · 되돌림 · 삭제, mergetool 파일 이름, 공백 이름) |
+
+### 확인한 것 (같은 저장소)
+
+| 확인 | 결과 |
+|---|---|
+| 충돌 네 칸 머리 | **`병합 충돌 · REMOTE = feature/theirs`**, 3-Way 콤보 안 보임. 화면 어디에도 "3-Way 안 씀" 없음 |
+| Take Theirs | 로그 **`10행 Theirs(feature/theirs) 반영`** |
+| Undo → Take Mine | 로그 **`10행 Mine(feature/mine) 으로 정함`** |
+| 한쪽이 지운 충돌(`Recipe/ToBeDeleted.cs`, 두 칸) | 콤보가 다시 보임 — 네 칸이 아니므로 지금 그대로 |
+| git | 충돌 26 그대로(저장 안 함) |
+
+MergeSaveTest 82건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
+콤보로 브랜치를 고르는 3-Way 는 병합이 아닐 때만 쓰는 길이라 화면으로는 따로 안 봤다 — 문구가 그대로인 것은 하네스로 확인했다.
+
## E-2. 폴더 비교 탭에 폴더를 하나씩 끌어다 놓으면 첫 칸 → 둘째 칸 차례로 (2026-09-14, 추가 요청, 완료)
사용자: "폴더비교 탭 첫번째 드래그 첫번째 폴더 경로에 들어가고 두번째는 드래그앤드롭은 두번째로 들어가게해줘 경로텍스트 박스에 안넣어도 그냥 화면에다 넣어둬 기능 동작하도록".
diff --git a/doc/history/changelog.md b/doc/history/changelog.md
index 85ae6ab..095d92b 100644
--- a/doc/history/changelog.md
+++ b/doc/history/changelog.md
@@ -8,6 +8,7 @@
| 날짜 | 항목 | 커밋 |
|---|---|---|
+| 2026-09-14 | **7차 A-2** — 병합 충돌 네 칸에서 Take Theirs 로그가 "10행 (3-Way 안 씀) 반영" 이고 Take Mine 은 로그가 없었다. 이제 "10행 Theirs(feature/theirs) 반영" · "10행 Mine(feature/mine) 으로 정함". 충돌 네 칸 머리는 3-Way 콤보 대신 "병합 충돌 · REMOTE = 상대". 브랜치 3-Way 문구는 그대로 | 아래 |
| 2026-09-14 | **7차 E-2** — 폴더 비교 화면 아무 데나 폴더를 하나 놓으면 늘 첫 칸에 들어가 두 번째 폴더가 첫 폴더를 덮어썼다. 놓는 차례대로 첫 칸 → 둘째 칸(양쪽이 차면 바로 비교), 경로 칸 위에 놓은 것도 차례에 친다. 탐색기에서 끌어다 놓아 확인 | 아래 |
| 2026-09-14 | **7차 E-3** — 켤 때 사용자 이름 창을 Alt+F4 로 닫으면 이름 없이 본 창을 쓸 수 있었고 창도 끌려 움직였다. 저장 전에는 닫히지 않고 움직이지 않게(플랫폼 `UserNameDialog`, 확인 받고 `D:\UbisamPlatform\bin` 배포). MergeHub 코드 변경 없음 | 아래 |
| 2026-09-14 | **7차 A-1** — 마지막 충돌을 [Save] 하면 파일 비교 탭이 "남은 차이 6줄" 로 떨어져 덜 푼 것처럼 보이던 것. 병합 중 충돌 0 이면 두 칸 요약이 "충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 N줄", BASE 제목에 "병합 전 내 쪽". E-1 때 못 돌린 MergeSaveTest 기대값도 [Save] 로 | 아래 |
diff --git a/doc/진행상황.md b/doc/진행상황.md
index 94dd3c4..534b1a7 100644
--- a/doc/진행상황.md
+++ b/doc/진행상황.md
@@ -151,7 +151,7 @@
| 상태 | 항목 |
|---|---|
| **완료** | A-1 마지막 충돌을 저장하면 "남은 차이" 가 뜬다 — 병합 중 충돌 0 이면 "충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 N줄", 제목에 "병합 전 내 쪽" |
-| 대기 | A-2 3분할에서 줄을 골라도 로그는 "3-Way 안 씀" 이라고 한다 |
+| **완료** | A-2 3분할에서 줄을 골라도 로그는 "3-Way 안 씀" 이라고 한다 — 로그 "10행 Theirs(feature/theirs) 반영" · "Mine(feature/mine) 으로 정함", 충돌 네 칸 머리는 콤보 대신 "병합 충돌 · REMOTE = 상대" |
### B. 치우기
diff --git a/src/MergeHub/Services/MergeNames.cs b/src/MergeHub/Services/MergeNames.cs
index 9f4c6d0..6021243 100644
--- a/src/MergeHub/Services/MergeNames.cs
+++ b/src/MergeHub/Services/MergeNames.cs
@@ -61,6 +61,43 @@ namespace MergeHub.Services
/// - 남는 것이 없으면 를 쓴다.
///
///
+ ///
+ /// 네 칸에서 줄을 고를 때 로그에 적을 쪽 이름(7차 A-2).
+ ///
+ /// 병합 충돌(또는 git mergetool 세 벌)이면 Theirs(feature/theirs) · Mine(feature/mine) 처럼 어느 쪽인지와 이름을 함께.
+ /// 예전에는 3-Way 콤보 값을 그대로 써서, 콤보를 안 건드리고 네 칸을 띄우는 충돌 파일에서 "(3-Way 안 씀) 반영" 이라고 적혔다.
+ /// 콤보로 고른 브랜치 3-Way 는 지금처럼 브랜치 이름만 쓴다.
+ ///
+ public static string SideLabel(bool mine, string? name, bool mergeSides)
+ {
+ var trimmed = string.IsNullOrWhiteSpace(name) ? null : name!.Trim();
+ if (!mergeSides) return trimmed ?? (mine ? "내 원본" : "REMOTE");
+
+ var side = mine ? "Mine" : "Theirs";
+ return trimmed is null ? side : $"{side}({trimmed})";
+ }
+
+ /// Take Theirs 로그. 상대 쪽에 없는 줄이면 지운 것으로 적는다.
+ public static string TakeTheirsLog(string? number, string? theirs, bool hasLine, bool mergeSides)
+ {
+ var label = SideLabel(mine: false, theirs, mergeSides);
+ return hasLine ? $"{number}행 {label} 반영" : $"{number}행 삭제({label} 에 없음)";
+ }
+
+ ///
+ /// Take Mine 로그. 이미 내 것과 같으면 "정함" 이라고 적는다 - 예전에는 아무것도 안 적어 무엇을 골랐는지 로그에 없었다.
+ /// 콤보로 고른 브랜치 3-Way 에서는 지금 문구("내 원본으로 되돌림")를 그대로 쓴다.
+ ///
+ public static string TakeMineLog(string? number, string? head, bool hasLine, bool alreadySame, bool mergeSides)
+ {
+ if (!mergeSides)
+ return hasLine ? $"{number}행 내 원본으로 되돌림" : $"{number}행 삭제(내 원본에 없음)";
+
+ var label = SideLabel(mine: true, head, mergeSides: true);
+ if (alreadySame) return $"{number}행 {label} 으로 정함";
+ return hasLine ? $"{number}행 {label} 으로 되돌림" : $"{number}행 삭제({label} 에 없음)";
+ }
+
public static string CleanMergeMessage(string? raw, string? theirs, string? head)
{
var lines = (raw ?? string.Empty).Replace("\r\n", "\n").Split('\n')
diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs
index d1ee5c3..c06dcb1 100644
--- a/src/MergeHub/ViewModels/HomeViewModel.cs
+++ b/src/MergeHub/ViewModels/HomeViewModel.cs
@@ -222,6 +222,8 @@ namespace MergeHub.ViewModels
: Path.GetFileName(request.Base);
LocalHeader = Path.GetFileName(request.Merged);
RemoteHeader = $"REMOTE · {Path.GetFileName(request.Remote)}";
+ _theirsSideName = Path.GetFileName(request.Remote);
+ _mineSideName = Path.GetFileName(request.Local);
_originalLocalText = BuildLocalText();
SyncEditorFromLines();
@@ -1286,8 +1288,11 @@ namespace MergeHub.ViewModels
if (!IsGitMode) return;
// 행을 싣기 전에 틀부터 바꾼다. 세 칸 행을 두 칸 틀에 실으면 REMOTE 칸이 안 보인다.
+ _theirsSideName = isConflict ? theirsName ?? "THEIRS" : null;
+ _mineSideName = null;
SetConflictThreeWay(isConflict && !deletion.IsDeletion);
SetDeletion(deletion, theirsName);
+ OnPropertyChanged(nameof(ConflictSideText));
Lines.Clear();
foreach (var row in rows) Lines.Add(row);
@@ -1684,6 +1689,29 @@ namespace MergeHub.ViewModels
///
private bool _conflictThreeWay;
+ ///
+ /// 병합 상대 · 내 쪽 이름. 충돌 파일(상대 브랜치)이나 git mergetool 세 벌(파일 이름)을 열 때 정한다(7차 A-2).
+ /// 콤보 값()은 이때 (3-Way 안 씀) 이라 로그와 머리에 쓰면 틀린다.
+ ///
+ private string? _theirsSideName;
+ private string? _mineSideName;
+
+ /// 줄을 고를 때 병합의 두 쪽(Theirs · Mine)으로 말하는지. 콤보로 고른 브랜치 3-Way 는 아니다.
+ private bool TakesMergeSides => _conflictThreeWay || _toolThreeWay;
+
+ private string? TheirsSideName => TakesMergeSides ? _theirsSideName : RemoteBranch;
+
+ private string? MineSideName => _toolThreeWay ? _mineSideName : _workspace.CurrentBranch;
+
+ /// 병합 충돌 파일을 네 칸으로 보는 중. 머리에서 3-Way 콤보 대신 상대 이름을 보인다.
+ public bool IsConflictThreeWay => IsGitMode && _conflictThreeWay;
+
+ /// 3-Way 콤보를 보일지. 충돌 네 칸일 때는 콤보가 가리키는 것이 없어 감춘다.
+ public bool ShowBranchCombo => !IsConflictThreeWay;
+
+ /// 충돌 네 칸일 때 콤보 자리에 보이는 글.
+ public string ConflictSideText => $"병합 충돌 · REMOTE = {_theirsSideName ?? "THEIRS"}";
+
private void SetConflictThreeWay(bool on)
{
if (_conflictThreeWay == on) return;
@@ -1700,6 +1728,8 @@ namespace MergeHub.ViewModels
OnPropertyChanged(nameof(LocalTitle));
OnPropertyChanged(nameof(SourceHeaderHeight));
OnPropertyChanged(nameof(IsMergeComplete));
+ OnPropertyChanged(nameof(IsConflictThreeWay));
+ OnPropertyChanged(nameof(ShowBranchCombo));
}
public bool IsTwoWay => !IsThreeWay;
@@ -1805,13 +1835,18 @@ namespace MergeHub.ViewModels
// 내용이 안 바뀌므로 다시 정렬하면 이 표시가 사라진다 - BASE 줄 번호로 따로 붙들어 둔다.
line.IsApplied = true;
MarkApplied(line);
+
+ // 병합의 두 쪽 중 내 것을 고른 것이다 - 내용은 안 바뀌어도 무엇을 골랐는지 로그에 남긴다(7차 A-2).
+ if (TakesMergeSides)
+ _workspace.AppendLog(MergeNames.TakeMineLog((line.LocalNumber ?? line.BaseNumber)?.ToString(),
+ MineSideName, afterHasLocal, alreadySame: true, mergeSides: true));
+
AfterEdit();
return;
}
- var description = afterHasLocal
- ? $"{line.LocalNumber}행 내 원본으로 되돌림"
- : $"{line.LocalNumber}행 삭제(내 원본에 없음)";
+ var description = MergeNames.TakeMineLog(line.LocalNumber?.ToString(), MineSideName,
+ afterHasLocal, alreadySame: false, TakesMergeSides);
line.LocalText = after;
line.HasLocal = afterHasLocal;
@@ -1876,9 +1911,9 @@ namespace MergeHub.ViewModels
if (beforeHasLocal == afterHasLocal && string.Equals(before, after, StringComparison.Ordinal))
return;
- var description = line.HasRemote
- ? $"{line.RemoteNumber}행 {RemoteBranch} 반영"
- : $"{line.LocalNumber}행 삭제({RemoteBranch} 에 없음)";
+ var description = MergeNames.TakeTheirsLog(
+ (line.HasRemote ? line.RemoteNumber : line.LocalNumber)?.ToString(),
+ TheirsSideName, line.HasRemote, TakesMergeSides);
line.LocalText = after;
line.HasLocal = afterHasLocal;
diff --git a/src/MergeHub/Views/HomeView.xaml b/src/MergeHub/Views/HomeView.xaml
index 4e2832e..dfd5257 100644
--- a/src/MergeHub/Views/HomeView.xaml
+++ b/src/MergeHub/Views/HomeView.xaml
@@ -493,8 +493,15 @@
VerticalAlignment="Center" Margin="0,0,6,0"/>
+
+