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"/> + +