7차 C-1: pull 로 받은 충돌도 [Merge] 와 같은 뒷일(머지 주석 자동 풀기 · 알림 · 커밋 메시지)
pull 은 Git.Pull 만 불러 머지 주석만 다른 충돌까지 사람에게 물었고(26 · 0/26), 알림도 커밋 메시지도 없었다. MergeAsync 의 뒷일을 AfterMerge 로 빼 pull 도 부른다(24 · 2/26 · 같은 알림). pull 병합 커밋 메시지는 git 과 같은 "Merge remote-tracking branch 'origin/feature/mine' into feature/mine". bare 원격으로 화면 확인, [Merge] 회귀 없음. MergeSaveTest 93건 통과. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
bb6bd655a5
commit
c4104288de
@ -123,6 +123,53 @@ MergeSaveTest 82건 통과. 빌드 경고 0 · 오류 0. 설정 파일은 바이
|
|||||||
|
|
||||||
MergeSaveTest 88건 통과. 빌드 경고 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, 추가 요청, 완료)
|
## E-2. 폴더 비교 탭에 폴더를 하나씩 끌어다 놓으면 첫 칸 → 둘째 칸 차례로 (2026-09-14, 추가 요청, 완료)
|
||||||
|
|
||||||
사용자: "폴더비교 탭 첫번째 드래그 첫번째 폴더 경로에 들어가고 두번째는 드래그앤드롭은 두번째로 들어가게해줘 경로텍스트 박스에 안넣어도 그냥 화면에다 넣어둬 기능 동작하도록".
|
사용자: "폴더비교 탭 첫번째 드래그 첫번째 폴더 경로에 들어가고 두번째는 드래그앤드롭은 두번째로 들어가게해줘 경로텍스트 박스에 안넣어도 그냥 화면에다 넣어둬 기능 동작하도록".
|
||||||
|
|||||||
@ -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차 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차 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-2** — 폴더 비교 화면 아무 데나 폴더를 하나 놓으면 늘 첫 칸에 들어가 두 번째 폴더가 첫 폴더를 덮어썼다. 놓는 차례대로 첫 칸 → 둘째 칸(양쪽이 차면 바로 비교), 경로 칸 위에 놓은 것도 차례에 친다. 탐색기에서 끌어다 놓아 확인 | 아래 |
|
||||||
|
|||||||
@ -163,7 +163,7 @@
|
|||||||
|
|
||||||
| 상태 | 항목 |
|
| 상태 | 항목 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 대기 | C-1 pull 이 낸 충돌에는 머지 주석 자동 풀기가 안 걸린다 |
|
| **완료** | C-1 pull 이 낸 충돌에는 머지 주석 자동 풀기가 안 걸린다 — pull 도 [Merge] 와 같은 뒷일(주석 자동 풀기 · 알림 · 진행 줄), 커밋 메시지 "Merge remote-tracking branch 'origin/…' into …" |
|
||||||
| 대기 | C-2 rebase · cherry-pick 충돌을 네 칸으로 끝까지 |
|
| 대기 | C-2 rebase · cherry-pick 충돌을 네 칸으로 끝까지 |
|
||||||
|
|
||||||
### D. 확인
|
### D. 확인
|
||||||
|
|||||||
@ -50,6 +50,21 @@ namespace MergeHub.Services
|
|||||||
: $"Merge branch '{theirs!.Trim()}'{into}";
|
: $"Merge branch '{theirs!.Trim()}'{into}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// pull 로 병합했을 때의 기본 메시지. git 명령으로 추적 브랜치를 병합할 때와 같은 모양이다(7차 C-1).
|
||||||
|
/// <c>Merge remote-tracking branch 'origin/feature/mine' into feature/mine</c>
|
||||||
|
///
|
||||||
|
/// 예전에는 pull 뒤 커밋 메시지 칸이 비어 있었고, 병합 커밋이 들어오는 커밋을 가리키는 <b>로컬</b> 브랜치 이름을 대신 썼다 -
|
||||||
|
/// 받아 온 원격 브랜치가 무엇인지 이력에 남지 않았다. 추적 브랜치 이름을 모르면 <see cref="BranchMergeMessage"/> 와 같게 줄인다.
|
||||||
|
/// </summary>
|
||||||
|
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}";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// git 이 남긴 병합 메시지(MERGE_MSG)를 커밋에 쓸 모양으로 다듬는다(6차 B-3).
|
/// git 이 남긴 병합 메시지(MERGE_MSG)를 커밋에 쓸 모양으로 다듬는다(6차 B-3).
|
||||||
///
|
///
|
||||||
|
|||||||
@ -179,13 +179,22 @@ namespace MergeHub.ViewModels
|
|||||||
});
|
});
|
||||||
|
|
||||||
[RelayCommand(CanExecute = nameof(IsOpen))]
|
[RelayCommand(CanExecute = nameof(IsOpen))]
|
||||||
private Task PullAsync() => _workspace.RunAndRefreshAsync("pull", () =>
|
private Task PullAsync()
|
||||||
|
{
|
||||||
|
// 목록은 화면 스레드의 것이라 작업에 들어가기 전에 읽어 둔다.
|
||||||
|
var tracked = _workspace.Branches.FirstOrDefault(b => b.IsCurrentHead)?.TrackedBranch;
|
||||||
|
|
||||||
|
return _workspace.RunAndRefreshAsync("pull", () =>
|
||||||
{
|
{
|
||||||
_workspace.ApplyCredentials();
|
_workspace.ApplyCredentials();
|
||||||
var result = _workspace.Git.Pull(_workspace.RemoteName);
|
var result = _workspace.Git.Pull(_workspace.RemoteName);
|
||||||
_workspace.MarkFetched();
|
_workspace.MarkFetched();
|
||||||
// 결과 한 줄은 GitService 가 로그에 적는다(Pull 은 Merge 를 거친다). 여기서 또 적으면 두 번 찍힌다(6차 C-1).
|
|
||||||
|
// pull 도 병합이다. 머지 주석 자동 풀기 · 알림 · 병합 커밋 메시지를 [Merge] 와 같은 길로(7차 C-1).
|
||||||
|
// 예전에는 여기서 아무것도 안 해 주석만 다른 충돌까지 사람에게 물었고, 알림도 커밋 메시지도 없었다.
|
||||||
|
AfterMerge(result, MergeNames.PullMergeMessage(tracked, _workspace.CurrentBranch));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand(CanExecute = nameof(IsOpen))]
|
[RelayCommand(CanExecute = nameof(IsOpen))]
|
||||||
private Task PushAsync() => _workspace.RunAndRefreshAsync("push", () =>
|
private Task PushAsync() => _workspace.RunAndRefreshAsync("push", () =>
|
||||||
@ -229,7 +238,15 @@ namespace MergeHub.ViewModels
|
|||||||
{
|
{
|
||||||
var branch = SelectedBranch!.FriendlyName;
|
var branch = SelectedBranch!.FriendlyName;
|
||||||
var result = _workspace.Git.Merge(branch, commitOnSuccess: false);
|
var result = _workspace.Git.Merge(branch, commitOnSuccess: false);
|
||||||
|
AfterMerge(result, MergeNames.BranchMergeMessage(branch, _workspace.CurrentBranch));
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 병합(또는 pull) 결과를 받은 뒤 할 일. 작업 스레드에서 부른다(7차 C-1 에서 [Merge] 와 pull 이 함께 쓰게 뺐다).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="defaultMessage">커밋 메시지 칸이 비어 있고 병합 커밋이 남았을 때 채울 메시지.</param>
|
||||||
|
private void AfterMerge(MergeResultInfo result, string defaultMessage)
|
||||||
|
{
|
||||||
// 머지 주석만 다른 충돌은 사람에게 묻지 않고 푼다. 양쪽 주석을 다 남긴다(6차 B-5).
|
// 머지 주석만 다른 충돌은 사람에게 묻지 않고 푼다. 양쪽 주석을 다 남긴다(6차 B-5).
|
||||||
IReadOnlyList<string> noteOnly = result.HasConflicts && _workspace.Settings.IgnoreMergeNotes
|
IReadOnlyList<string> noteOnly = result.HasConflicts && _workspace.Settings.IgnoreMergeNotes
|
||||||
? _workspace.Git.ResolveNoteOnlyConflicts()
|
? _workspace.Git.ResolveNoteOnlyConflicts()
|
||||||
@ -243,8 +260,10 @@ namespace MergeHub.ViewModels
|
|||||||
if (noteOnly.Count > 0)
|
if (noteOnly.Count > 0)
|
||||||
_workspace.AppendLog($"머지 주석만 다른 충돌 {noteOnly.Count}개 파일은 자동으로 풀었습니다. 남은 충돌 {remaining}건.");
|
_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;
|
var autoNote = noteOnly.Count > 0 ? $" (머지 주석만 다른 {noteOnly.Count}건은 자동으로 풀림)" : string.Empty;
|
||||||
|
|
||||||
@ -255,7 +274,7 @@ namespace MergeHub.ViewModels
|
|||||||
else
|
else
|
||||||
MessageUtil.ShowToast(result.Message);
|
MessageUtil.ShowToast(result.Message);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
private bool CanAbort() => _workspace.IsMergeInProgress || _workspace.IsRebaseInProgress;
|
private bool CanAbort() => _workspace.IsMergeInProgress || _workspace.IsRebaseInProgress;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user