diff --git a/doc/history/2026-09-14-7차.md b/doc/history/2026-09-14-7차.md
index caa622a..4fb6c43 100644
--- a/doc/history/2026-09-14-7차.md
+++ b/doc/history/2026-09-14-7차.md
@@ -123,6 +123,53 @@ MergeSaveTest 82건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이
MergeSaveTest 88건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
+## C-1. pull 이 낸 충돌에는 머지 주석 자동 풀기가 안 걸린다 (2026-09-14, 완료)
+
+### 준비 — 원격을 흉내 낸 저장소
+
+만든 저장소를 `git clone --bare` 로 떠서 `origin` 으로 달고, 그 bare 저장소의 `feature/mine` 을 `feature/theirs` 커밋으로 옮겼다.
+내 `feature/mine` 이 `origin/feature/mine` 을 추적하게 하면 pull 이 [Merge] 와 **같은 병합 기준 · 같은 26개 충돌**을 낸다.
+(bare 폴더는 지우지 않고 시각을 붙인 새 이름으로 만들었다.)
+
+### 고치기 전에 다시 났다
+
+| 확인 | [Merge] (6차 D-1) | **Pull** |
+|---|---|---|
+| 알림 | 충돌 24건 (머지 주석만 다른 2건은 자동으로 풀림) … | **없음** |
+| 로그 | 충돌 26건 · 자동 해결 두 줄 · "자동으로 풀었습니다. 남은 충돌 24건." | "충돌 26건 - 해결이 필요합니다." 뿐 |
+| git 충돌 | 24 | **26** (주석만 다른 2개도 남음) |
+| 진행 줄 | 남은 충돌 24개 · 푼 것 2개 (2/26) | **남은 충돌 26개 · 푼 것 0개 (0/26)** |
+| Git 탭 커밋 메시지 칸 | Merge branch 'feature/theirs' into feature/mine | **비어 있음** |
+| 병합 커밋 제목 | - | `Merge branch 'feature/theirs' into feature/mine` — 받아 온 `origin/feature/mine` 이 아니라 같은 커밋을 가리키는 **로컬 브랜치** 이름 |
+
+### 원인
+
+- `GitViewModel.PullAsync` 는 `Git.Pull` 만 불렀다. 머지 주석 자동 풀기(`ResolveNoteOnlyConflicts`) · 알림 · 커밋 메시지 기본값은 모두 `MergeAsync` 안에만 있었다.
+- 메시지 칸이 비면 병합 커밋이 `CleanMergeMessage` 로 상대 이름을 찾는데, 들어오는 커밋을 가리키는 **로컬 브랜치를 먼저** 본다. 이번 준비처럼 같은 커밋을 가리키는 로컬 브랜치가 있으면 그 이름이 들어간다.
+
+### 고친 것
+
+| 파일 | 무엇 |
+|---|---|
+| `ViewModels/GitViewModel.cs` | `MergeAsync` 의 뒷일을 `AfterMerge(결과, 기본 메시지)` 로 빼고 `PullAsync` 도 부른다. 기본 메시지는 병합 커밋이 남을 때(충돌 · 병합됨)만 채운다 — 이미 최신 · 앞으로 감기면 채우지 않는다 |
+| `Services/MergeNames.cs` | `PullMergeMessage(추적 브랜치, 내 브랜치)` — git 과 같은 `Merge remote-tracking branch 'origin/x' into y`. 추적 브랜치를 모르면 `Merge into y` |
+| 하네스 `MergeSaveTest` | pull 메시지 검사 5건(모양 · 공백 · 추적 모름 · 내 브랜치 모름 · 다시 읽으면 원격 브랜치 이름) |
+
+추적 브랜치 이름은 작업에 들어가기 전에 화면 스레드에서 읽는다(브랜치 목록이 화면의 것이다).
+
+### 확인한 것 (저장소 · bare 원격 새로 만들어)
+
+| 확인 | ① Pull | ② [Merge] (회귀) |
+|---|---|---|
+| 알림 | **충돌 24건 (머지 주석만 다른 2건은 자동으로 풀림) - 충돌 탭에서 …** | 같음 |
+| 로그 | fetch → 병합 시작 `origin/feature/mine -> feature/mine` → 충돌 26건 → 자동 해결 `Unit46.cs` · `Unit45.cs` → 남은 충돌 24건 | 병합 시작 `feature/theirs -> feature/mine` 부터 같음 |
+| git 충돌 | **24** | 24 |
+| 진행 줄 | **남은 충돌 24개 · 푼 것 2개 (2/26)** | 같음 |
+| 커밋 메시지 칸 | **Merge remote-tracking branch 'origin/feature/mine' into feature/mine** | Merge branch 'feature/theirs' into feature/mine |
+| 병합 커밋 (git 으로 풀고 새로고침 → [병합 커밋]) | `7280418` 부모 둘 · **Merge remote-tracking branch 'origin/feature/mine' into feature/mine** | - |
+
+MergeSaveTest 93건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
+
## E-2. 폴더 비교 탭에 폴더를 하나씩 끌어다 놓으면 첫 칸 → 둘째 칸 차례로 (2026-09-14, 추가 요청, 완료)
사용자: "폴더비교 탭 첫번째 드래그 첫번째 폴더 경로에 들어가고 두번째는 드래그앤드롭은 두번째로 들어가게해줘 경로텍스트 박스에 안넣어도 그냥 화면에다 넣어둬 기능 동작하도록".
diff --git a/doc/history/changelog.md b/doc/history/changelog.md
index 38de13d..e48518f 100644
--- a/doc/history/changelog.md
+++ b/doc/history/changelog.md
@@ -8,6 +8,7 @@
| 날짜 | 항목 | 커밋 |
|---|---|---|
+| 2026-09-14 | **7차 C-1** — pull 로 받은 충돌은 머지 주석만 다른 파일까지 사람에게 물었고(26 · 0/26), 알림도 커밋 메시지도 없었다. [Merge] 의 뒷일을 `AfterMerge` 로 빼 pull 도 같게(24 · 2/26 · 같은 알림). pull 병합 커밋 메시지는 git 과 같은 "Merge remote-tracking branch 'origin/feature/mine' into feature/mine" | 아래 |
| 2026-09-14 | **7차 B-1** — 병합 때 적는 처음 충돌 목록(`.git/MERGEHUB_CONFLICTS`)이 병합 커밋 · 작업 취소 · 터미널에서 끝낸 병합 뒤에도 남았다. MERGE_HEAD 가 없거나 다른 병합의 것이면 병합 커밋 · 작업 취소 직후와 상태를 다시 읽을 때마다 지운다. 병합 중에는 그대로라 "푼 것 M개" 는 이어진다 | 아래 |
| 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** — 폴더 비교 화면 아무 데나 폴더를 하나 놓으면 늘 첫 칸에 들어가 두 번째 폴더가 첫 폴더를 덮어썼다. 놓는 차례대로 첫 칸 → 둘째 칸(양쪽이 차면 바로 비교), 경로 칸 위에 놓은 것도 차례에 친다. 탐색기에서 끌어다 놓아 확인 | 아래 |
diff --git a/doc/진행상황.md b/doc/진행상황.md
index bff0fcc..59940c7 100644
--- a/doc/진행상황.md
+++ b/doc/진행상황.md
@@ -163,7 +163,7 @@
| 상태 | 항목 |
|---|---|
-| 대기 | C-1 pull 이 낸 충돌에는 머지 주석 자동 풀기가 안 걸린다 |
+| **완료** | C-1 pull 이 낸 충돌에는 머지 주석 자동 풀기가 안 걸린다 — pull 도 [Merge] 와 같은 뒷일(주석 자동 풀기 · 알림 · 진행 줄), 커밋 메시지 "Merge remote-tracking branch 'origin/…' into …" |
| 대기 | C-2 rebase · cherry-pick 충돌을 네 칸으로 끝까지 |
### D. 확인
diff --git a/src/MergeHub/Services/MergeNames.cs b/src/MergeHub/Services/MergeNames.cs
index 6021243..7d32da2 100644
--- a/src/MergeHub/Services/MergeNames.cs
+++ b/src/MergeHub/Services/MergeNames.cs
@@ -50,6 +50,21 @@ namespace MergeHub.Services
: $"Merge branch '{theirs!.Trim()}'{into}";
}
+ ///
+ /// pull 로 병합했을 때의 기본 메시지. git 명령으로 추적 브랜치를 병합할 때와 같은 모양이다(7차 C-1).
+ /// Merge remote-tracking branch 'origin/feature/mine' into feature/mine
+ ///
+ /// 예전에는 pull 뒤 커밋 메시지 칸이 비어 있었고, 병합 커밋이 들어오는 커밋을 가리키는 로컬 브랜치 이름을 대신 썼다 -
+ /// 받아 온 원격 브랜치가 무엇인지 이력에 남지 않았다. 추적 브랜치 이름을 모르면 와 같게 줄인다.
+ ///
+ public static string PullMergeMessage(string? trackedBranch, string? head)
+ {
+ if (string.IsNullOrWhiteSpace(trackedBranch)) return BranchMergeMessage(null, head);
+
+ var into = string.IsNullOrWhiteSpace(head) ? string.Empty : $" into {head!.Trim()}";
+ return $"Merge remote-tracking branch '{trackedBranch!.Trim()}'{into}";
+ }
+
///
/// git 이 남긴 병합 메시지(MERGE_MSG)를 커밋에 쓸 모양으로 다듬는다(6차 B-3).
///
diff --git a/src/MergeHub/ViewModels/GitViewModel.cs b/src/MergeHub/ViewModels/GitViewModel.cs
index be8e8c9..b3d8d25 100644
--- a/src/MergeHub/ViewModels/GitViewModel.cs
+++ b/src/MergeHub/ViewModels/GitViewModel.cs
@@ -179,13 +179,22 @@ namespace MergeHub.ViewModels
});
[RelayCommand(CanExecute = nameof(IsOpen))]
- private Task PullAsync() => _workspace.RunAndRefreshAsync("pull", () =>
+ private Task PullAsync()
{
- _workspace.ApplyCredentials();
- var result = _workspace.Git.Pull(_workspace.RemoteName);
- _workspace.MarkFetched();
- // 결과 한 줄은 GitService 가 로그에 적는다(Pull 은 Merge 를 거친다). 여기서 또 적으면 두 번 찍힌다(6차 C-1).
- });
+ // 목록은 화면 스레드의 것이라 작업에 들어가기 전에 읽어 둔다.
+ var tracked = _workspace.Branches.FirstOrDefault(b => b.IsCurrentHead)?.TrackedBranch;
+
+ return _workspace.RunAndRefreshAsync("pull", () =>
+ {
+ _workspace.ApplyCredentials();
+ var result = _workspace.Git.Pull(_workspace.RemoteName);
+ _workspace.MarkFetched();
+
+ // pull 도 병합이다. 머지 주석 자동 풀기 · 알림 · 병합 커밋 메시지를 [Merge] 와 같은 길로(7차 C-1).
+ // 예전에는 여기서 아무것도 안 해 주석만 다른 충돌까지 사람에게 물었고, 알림도 커밋 메시지도 없었다.
+ AfterMerge(result, MergeNames.PullMergeMessage(tracked, _workspace.CurrentBranch));
+ });
+ }
[RelayCommand(CanExecute = nameof(IsOpen))]
private Task PushAsync() => _workspace.RunAndRefreshAsync("push", () =>
@@ -229,7 +238,15 @@ namespace MergeHub.ViewModels
{
var branch = SelectedBranch!.FriendlyName;
var result = _workspace.Git.Merge(branch, commitOnSuccess: false);
+ AfterMerge(result, MergeNames.BranchMergeMessage(branch, _workspace.CurrentBranch));
+ });
+ ///
+ /// 병합(또는 pull) 결과를 받은 뒤 할 일. 작업 스레드에서 부른다(7차 C-1 에서 [Merge] 와 pull 이 함께 쓰게 뺐다).
+ ///
+ /// 커밋 메시지 칸이 비어 있고 병합 커밋이 남았을 때 채울 메시지.
+ private void AfterMerge(MergeResultInfo result, string defaultMessage)
+ {
// 머지 주석만 다른 충돌은 사람에게 묻지 않고 푼다. 양쪽 주석을 다 남긴다(6차 B-5).
IReadOnlyList noteOnly = result.HasConflicts && _workspace.Settings.IgnoreMergeNotes
? _workspace.Git.ResolveNoteOnlyConflicts()
@@ -243,8 +260,10 @@ namespace MergeHub.ViewModels
if (noteOnly.Count > 0)
_workspace.AppendLog($"머지 주석만 다른 충돌 {noteOnly.Count}개 파일은 자동으로 풀었습니다. 남은 충돌 {remaining}건.");
- if (string.IsNullOrWhiteSpace(CommitMessage))
- CommitMessage = $"Merge branch '{branch}' into {_workspace.CurrentBranch}";
+ // 병합 커밋이 남는 경우에만 채운다 - 이미 최신이거나 앞으로 감기면 커밋할 병합이 없다.
+ if (string.IsNullOrWhiteSpace(CommitMessage) &&
+ (result.HasConflicts || result.Outcome == MergeOutcome.Merged))
+ CommitMessage = defaultMessage;
var autoNote = noteOnly.Count > 0 ? $" (머지 주석만 다른 {noteOnly.Count}건은 자동으로 풀림)" : string.Empty;
@@ -255,7 +274,7 @@ namespace MergeHub.ViewModels
else
MessageUtil.ShowToast(result.Message);
});
- });
+ }
private bool CanAbort() => _workspace.IsMergeInProgress || _workspace.IsRebaseInProgress;