코드 변경 없음. 새 시험 저장소에서 MergeHub 만으로 네 길 모두 커밋(rebase 끝)까지 갔다. 줄끝 · BOM 바뀐 파일 0, A-2 · B-1 다시 안 남, MERGED 줄 번호 안 잘림. 새로 걸린 것(고치지 않음 → 8차): - N1 파일 비교 탭을 처음 여는 것이 [3분할로 열기] 면 첫 충돌 파일이 보이고, 그 화면을 [Save] 하면 고른 파일에 그 내용이 써진다(Unit47 ← Unit15) - N2 rebase · cherry-pick 마지막 저장 뒤 "남은 차이"(A-1 은 병합만) - N3 MERGED 칸 번호가 결과 파일 번호가 아님 - N4 바뀌는 것 없는 cherry-pick 에서 [커밋] 이 켜져 실패 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
503 lines
46 KiB
Markdown
503 lines
46 KiB
Markdown
# 7차 — 병합 화면이 사실대로 말하게 · 병합 말고 다른 충돌 길 (2026-09-14 ~)
|
||
|
||
지시서: [../작업지시/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. 설정 파일은 바이트 그대로 되돌림.
|
||
|
||
## 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 는 병합이 아닐 때만 쓰는 길이라 화면으로는 따로 안 봤다 — 문구가 그대로인 것은 하네스로 확인했다.
|
||
|
||
## B-1. 병합 커밋 뒤에도 `.git/MERGEHUB_CONFLICTS` 가 남는다 (2026-09-14, 완료)
|
||
|
||
### 고치기 전에 다시 났다 (새로 만든 저장소, MergeHub 로 병합)
|
||
|
||
| 때 | MERGE_HEAD | MERGEHUB_CONFLICTS |
|
||
|---|---|---|
|
||
| 병합 전 | 없음 | 없음 |
|
||
| MergeHub [Merge] 뒤 | 있음 | 있음 |
|
||
| [작업 취소] 뒤 | 없음 | **남음** |
|
||
| 다시 병합 → 터미널에서 풀고 커밋 → 앱 [새로고침] | 없음 | **남음** |
|
||
| (6차 D-1) MergeHub [병합 커밋] 뒤 | 없음 | **남음** |
|
||
|
||
### 원인
|
||
|
||
`GitService.RememberMergeConflicts` 가 병합 때 적기만 하고, 병합 커밋 · 작업 취소 · 상태 다시 읽기 어디에도 치우는 코드가 없었다.
|
||
첫 줄의 MERGE_HEAD 와 대조하므로(`GetMergeConflictTotal`) 다음 병합의 수가 틀리지는 않았다 - 남의 `.git` 에 우리 파일이 남는 것만 문제였다.
|
||
|
||
### 고친 것
|
||
|
||
| 파일 | 무엇 |
|
||
|---|---|
|
||
| `Services/MergeConflictRecord.cs` (새 파일) | `IsStale(MERGE_HEAD, 첫 줄)` — 병합 중이 아니거나, 빈 파일이거나, 첫 줄이 지금 MERGE_HEAD 와 다르면 쓸모없음 |
|
||
| `Services/GitService.cs` | `ForgetStaleMergeConflicts()` — 쓸모없으면 지운다. 잠김 등으로 못 지워도 다른 일을 막지 않는다. `CommitMerge` 뒤 · `AbortOperation`(작업 취소) 뒤에 부른다 |
|
||
| `Services/IGitService.cs` | 선언 |
|
||
| `Services/GitWorkspace.cs` | `ReadState` 처음에 부른다 — 새로고침 · 저장소 열기 · 모든 Git 작업 뒤. 터미널에서 끝낸 병합도 여기서 치운다 |
|
||
| 하네스 `MergeSaveTest` | `IsStale` 검사 6건(병합 아님 · 빈 MERGE_HEAD · 같은 병합은 둠 · 다른 병합 · 대소문자와 공백 · 빈 파일) |
|
||
|
||
### 확인한 것 (세 경우 모두 저장소를 새로 만들어)
|
||
|
||
| 경우 | 병합 중 | 끝난 뒤 |
|
||
|---|---|---|
|
||
| ① [Merge] → [작업 취소] | 파일 있음 · 진행 줄 "남은 충돌 24개 · 푼 것 2개 (2/26)" | MERGE_HEAD 없음 · **파일 없음** |
|
||
| ② [Merge] → git 으로 풀기만 → [새로고침] → [병합 커밋] | 다 풀고 새로고침해도 **파일 그대로** · "충돌 정리 끝 · 푼 것 26개" (병합 중에는 안 지운다) | 커밋 `5f9d5d9`(부모 둘) · **파일 없음** |
|
||
| ③ [Merge] → 터미널에서 풀고 커밋 → [새로고침] | 새로고침 전에는 파일 남음 | 새로고침 뒤 **파일 없음** |
|
||
|
||
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. 설정 파일은 바이트 그대로 되돌림.
|
||
|
||
## C-2. rebase · cherry-pick 충돌을 네 칸으로 끝까지 (2026-09-15, 완료)
|
||
|
||
### 준비
|
||
|
||
시험 저장소(`C1Repo`)를 그대로 썼다. `feature/mine`(내 쪽 작업) · `feature/theirs`(상대 쪽 작업)가 같은 바탕에서 커밋 하나씩이라
|
||
**rebase**(`feature/mine` 을 `feature/theirs` 위로)도 **cherry-pick**(상대 쪽 작업을 `feature/mine` 에)도 병합과 같은 26개 충돌을 낸다.
|
||
지시서는 생성기에 갈래를 더하라고 했지만 필요 없어서 바꾸지 않았다.
|
||
|
||
### 고치기 전에 다시 났다
|
||
|
||
**rebase** (Git 탭 [선택 브랜치 위로 rebase])
|
||
|
||
| # | 무엇 | 근거 |
|
||
|---|---|---|
|
||
| R1 | 네 칸 제목이 두 쪽을 말하지 않는다. rebase 에서는 LOCAL 이 **올릴 자리(`feature/theirs`)**, REMOTE 가 **다시 올리는 내 커밋**인데 | LOCAL `feature/theirs` · REMOTE **`REMOTE · THEIRS`** · 머리 글 **`병합 충돌 · REMOTE = THEIRS`** |
|
||
| R2 | Take Theirs 가 내 커밋 줄을 가져오는데 화면은 그 사정을 모른다 | `Common/Util/Unit15.cs` Take Theirs → `feature/mine` 에만 있는 줄 1/1 들어감 |
|
||
| R3 | 로그가 코드 이름을 적는다 | `rebase 1/1 단계에서 충돌 26건 - 해결 후 RebaseContinue() 를 호출하세요.` |
|
||
| R4 | 머지 주석 자동 풀기가 안 걸린다 | 충돌 26(병합은 24) |
|
||
| - | 끝내는 길은 됐다 | 다 풀자 [계속] 켜짐 · [병합 커밋] 꺼짐, [계속] → `rebase 완료 (1/1 단계)`, 이력 `내 쪽 작업` 이 `상대 쪽 작업` 위에 |
|
||
|
||
**cherry-pick**
|
||
|
||
| # | 무엇 | 근거 |
|
||
|---|---|---|
|
||
| C1 | **다른 브랜치의 커밋을 고를 수 없다.** Git 탭 이력은 HEAD 에서 닿는 커밋만 보인다 | 이력 목록에 `상대 쪽 작업` 없음. `GetCommits` 가 시작점 없이 `CommitFilter` 를 써서 libgit2 기본(HEAD)만 |
|
||
| C2 | 이미 있는 커밋(HEAD)을 cherry-pick 하면 `CHERRY_PICK_HEAD` 가 남는데 **진행 표시도 [작업 취소] 도 없다** — 빠져나올 길이 없다 | 로그 `cherry-pick 적용됨 - 확인 후 Commit() 을 호출하세요.` · 머리 표시 없음 · [작업 취소] 꺼짐 |
|
||
| C3 | 충돌 중 머리가 **"병합 진행 중"**, REMOTE `REMOTE · THEIRS`, 머리 글 `병합 충돌 · REMOTE = THEIRS` | git 으로 cherry-pick 을 시작해 앱으로 연 화면 |
|
||
| C4 | 충돌을 다 풀면 **진행 표시 · [작업 취소] · [병합 커밋] 이 모두 사라진다.** 끝내려면 변경 · 커밋 탭에서 메시지를 직접 쳐야 한다(원래 메시지 안 채워짐) | 다 푼 뒤 머리 표시 없음 · 작업 취소 꺼짐 · 병합 커밋 꺼짐. 메시지를 쳐서 [커밋] 하면 `CHERRY_PICK_HEAD` 는 치워짐 |
|
||
|
||
### 원인
|
||
|
||
- 화면이 충돌을 모두 "병합" 으로만 다뤘다. 진행 중인지는 `IsMergeInProgress`(병합 표시 **또는 충돌 있음**)로만 봐서, cherry-pick 은 충돌이 0 이 되면 진행 중이 아니게 됐다.
|
||
- 상대 이름은 MERGE_HEAD 로만 찾았다(`GetMergeTheirsName`) — rebase · cherry-pick 에는 MERGE_HEAD 가 없어 "THEIRS".
|
||
- 머지 주석 자동 풀기 · 알림은 [Merge] · pull 에만 걸려 있었다(7차 C-1).
|
||
|
||
### 고친 것
|
||
|
||
| 파일 | 무엇 |
|
||
|---|---|
|
||
| `Models/GitModels.cs` | `GitOperationKind`(None · Merge · Rebase · CherryPick · Revert) · `GitOperationState`(두 쪽 이름 · 들어오는 커밋 · 단계) |
|
||
| `Services/OperationLabels.cs` (새 파일) | 작업별 글 — 진행 표시(`rebase 1/1` · `cherry-pick 진행 중`), LOCAL 제목(rebase 는 `올릴 자리 feature/theirs`), REMOTE 제목(`다시 올리는 내 커밋 …` · `가져오는 커밋 …` · `되돌리는 커밋 …`), 네 칸 머리 글, 로그 이름, 끝내기 단추(병합 커밋 · 계속 · 커밋), 진행 줄(병합 글은 예전 그대로) |
|
||
| `Services/GitService.cs` | `GetOperationState` — git 작업 표시로 판단: rebase 는 `rebase-merge/onto` · `head-name` · 지금 단계 커밋, cherry-pick · revert 는 `CHERRY_PICK_HEAD` · `REVERT_HEAD`. `GetPendingCommitMessage`(원래 메시지, # 줄 뺌). `CommitPendingOperation` — cherry-pick 은 git 처럼 **원래 작성자**, 커밋한 사람은 지금 사용자. `GetCommits(allBranches)`. 로그의 `Commit()` · `RebaseContinue()` 문구를 [커밋] · [계속] 으로 |
|
||
| `Services/GitWorkspace.cs` | `OperationState` · `IsOperationInProgress`(충돌 수와 따로) · `ShowAllBranchesInHistory`. 진행 표시 · 진행 줄이 작업을 따른다 |
|
||
| `ViewModels/GitViewModel.cs` | 뒷일(`AfterConflicts`)을 병합 · pull · rebase 시작 · rebase 계속 · cherry-pick · revert 가 함께 쓴다 — 머지 주석 자동 풀기 · 알림("다 풀면 [계속] 으로 …") · cherry-pick · revert 메시지 채우기. `FinishOperationCommand` — 병합 커밋 / 계속 / 커밋. [작업 취소] 가 진행 중인 작업이면 켜짐 |
|
||
| `Views/GitView.xaml` | 충돌 탭 끝내기 단추 글자 · 명령이 작업을 따른다. 진행 줄은 `IsOperationInProgress` 로 보인다. 이력 탭에 **[모든 브랜치]** 체크(사용자 결정, 기본 꺼짐) |
|
||
| `ViewModels/HomeViewModel.cs` | 충돌 파일을 열 때 작업 상태로 LOCAL · REMOTE 제목 · 머리 글 · Take 로그 이름을 정한다. 병합 커밋 메시지 자동 채우기는 병합일 때만 |
|
||
| 하네스 `MergeSaveTest` | 작업별 글 검사 32건(진행 표시 · 칸 제목 · 머리 글 · 로그 이름 · 끝내기 단추 · 진행 줄, 병합 글이 예전과 같은지) |
|
||
|
||
### 확인한 것 (모두 저장소를 새로 만들어 MergeHub 만으로)
|
||
|
||
**① rebase**
|
||
|
||
| 때 | 결과 |
|
||
|---|---|
|
||
| [선택 브랜치 위로 rebase] | 알림 **`충돌 24건 (머지 주석만 다른 2건은 자동으로 풀림) - … 다 풀면 [계속] 으로 rebase 를 이어 갑니다.`** · 로그 `… 충돌 26건 - 풀고 나서 [계속] 을 누르세요.` + 자동 해결 두 줄 |
|
||
| 충돌 중 | 머리 **`rebase 1/1`** · [작업 취소] 켜짐 · 진행 줄 `남은 충돌 24개` · 끝내기 단추 **[계속]**(꺼짐) |
|
||
| 네 칸 (`Unit15.cs`) | LOCAL **`올릴 자리 feature/theirs`** · REMOTE **`REMOTE · 다시 올리는 내 커밋 a0fead2 내 쪽 작업`** · 머리 글 `rebase 충돌 · LOCAL = 올릴 자리 feature/theirs · REMOTE = 다시 올리는 내 커밋 a0fead2` · "3-Way 안 씀" 없음 |
|
||
| Take Theirs → Save | 로그 **`10행 Theirs(커밋 a0fead2) 반영`** |
|
||
| 23개 파일 단위 Accept Theirs · `Io/LineEnding.cs` 는 네 칸에서 Take Theirs → Save | 진행 줄 **`충돌 정리 끝 - [계속] 으로 rebase 를 이어 갑니다`** · [계속] 켜짐 |
|
||
| [계속] | `rebase 완료 (1/1 단계)` · 진행 표시 · [작업 취소] 사라짐. 이력 `c1296a7 내 쪽 작업` ← `1bdc05b 상대 쪽 작업` ← 바탕 |
|
||
| 결과 커밋 (부모와 바이트로) | 바뀐 파일 32 · **줄끝 · BOM · 인코딩이 부모와 다른 파일 0** · 충돌 표식 0 |
|
||
|
||
**② cherry-pick**
|
||
|
||
| 때 | 결과 |
|
||
|---|---|
|
||
| 이력 [모든 브랜치] | 끄면 `상대 쪽 작업` 없음 → 켜면 보임, 골라 [Cherry-pick] |
|
||
| 시작 | 알림 `충돌 24건 (…) - … 다 풀면 [커밋] 으로 cherry-pick 을 끝냅니다.` · 로그 `cherry-pick 충돌 26건 - 풀고 나서 충돌 탭의 [커밋] 으로 끝냅니다.` + 자동 해결 |
|
||
| 충돌 중 | 머리 **`cherry-pick 진행 중`** · [작업 취소] 켜짐 · 끝내기 단추 **[커밋]**(꺼짐) |
|
||
| 네 칸 | LOCAL `feature/mine` · REMOTE **`REMOTE · 가져오는 커밋 0862180 상대 쪽 작업`** · 머리 글 `cherry-pick 충돌 · REMOTE = 가져오는 커밋 …` · 로그 `10행 Theirs(커밋 …) 반영` |
|
||
| 23개 Accept Theirs(24 → 1) · `LineEnding.cs` 네 칸 → Save | 진행 줄 **`충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다`** · [커밋] 켜짐 · 진행 표시 그대로 |
|
||
| [커밋] (메시지 칸 비움) | `cherry-pick 커밋: ebe2a64 상대 쪽 작업` — **원래 메시지**, 부모 하나, `CHERRY_PICK_HEAD` 없어짐, 진행 표시 · [작업 취소] 사라짐 |
|
||
| 결과 커밋 | 바뀐 파일 32 · **줄끝 · BOM · 인코딩이 부모와 다른 파일 0** · 충돌 표식 0 · `LineEnding.cs` BOM · CRLF 그대로 |
|
||
|
||
**③ 바뀌는 것 없는 cherry-pick (HEAD 커밋을 다시)**
|
||
|
||
| 때 | 결과 |
|
||
|---|---|
|
||
| [Cherry-pick] | `CHERRY_PICK_HEAD` 생김 · 머리 **`cherry-pick 진행 중`** · **[작업 취소] 켜짐** (예전에는 둘 다 없었다) |
|
||
| [작업 취소] | `CHERRY_PICK_HEAD` 없어짐 · 표시 사라짐 |
|
||
|
||
MergeSaveTest 125건 · EncTest 48 · FolderTest 62 · ReportTest 31 · SearchTest 63 통과(`GitModels.cs` 를 함께 컴파일). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
|
||
|
||
### 확인하며 알게 된 것 · 남긴 것
|
||
|
||
- **파일 단위 Accept 는 고른 쪽 파일을 바이트째 쓴다.** 상대가 줄끝을 CRLF → LF 로 바꾼 `Io/LineEnding.cs` 를 파일 단위로 Accept Theirs 하면 그 줄끝이 그대로 들어온다(처음 확인에서 1개로 잡힘). 결함이 아니라 고른 대로다 — 6차 D-1 처럼 이런 파일은 네 칸에서 풀면 내 쪽(rebase 는 올릴 자리) 줄끝을 따른다.
|
||
- **원래 작성자 남기기는 이 저장소로 구별되지 않았다.** 시험 저장소의 모든 커밋 작성자가 같다(`시험`). 코드로만 확인했다.
|
||
- **③ 에서 [커밋] 도 켜진다.** 바뀐 것이 없어 누르면 빈 커밋 오류가 날 것으로 보인다. 로그 `적용됨 - 확인한 뒤 [커밋] 으로 끝냅니다` 도 이 경우엔 맞지 않다. 고치지 않고 적어 둔다(D-1 에서 다시 본다).
|
||
- revert 충돌은 같은 길(`AfterConflicts` · `CommitPendingOperation`)을 쓰지만 화면으로 끝까지는 안 봤다.
|
||
- 자동 조작 쪽: cherry-pick 첫 확인에서 [모든 브랜치] 를 켠 직후 목록 선택이 앱에 안 닿아 Accept 가 한 개만 풀렸다. 기다림을 넣고 다시 해 24 → 1 로 확인했다.
|
||
|
||
## D-1. 네 길을 처음부터 다시 끝까지 (2026-09-15, 완료)
|
||
|
||
지시서대로 **고치지 않고 적기만 했다.** 제품 코드는 한 줄도 안 바꿨다.
|
||
|
||
### 무엇으로 했나
|
||
|
||
- 길마다 시험 저장소를 `C1Repo` 로 새로 만들었다(실제 소스는 열지 않음). 충돌 26개(머지 주석만 다른 2개 포함) — 네 길 모두 같다.
|
||
- pull 은 저장소를 `git clone --bare` 로 떠 원격으로 달고, 그 원격의 `feature/mine` 을 상대 쪽 커밋으로 옮겨 추적하게 했다(7차 C-1 과 같은 준비).
|
||
- 네 길 모두 **같은 순서로 풀었다**(6차 D-1 과 같은 고르기):
|
||
1. 충돌 탭에서 같은 줄 충돌 15개(Unit10~24)를 골라 Accept Theirs 한 번
|
||
2. `Ui/Views/NewPanel.cs`(양쪽 새 파일)에 Accept Both → 묻는 창 [아니오]
|
||
3. [3분할로 열기] → 저장하면 저절로 열리는 다음 파일마다 [다음 충돌] + Take Theirs / Take Mine 번갈아 → [Save].
|
||
지운 파일 띠는 `ToBeDeleted` [파일 지우기] · `ToBeDeletedByMe` [파일 남기기]. 첫 파일에서 충돌이 남은 채 Save & Commit 을 한 번 누름
|
||
4. 끝내기 단추(병합 커밋 · 계속 · 커밋)
|
||
- 설정 `CSharpBraceStyle` 은 길마다 백업 → 끔 → 시험 → 원래 바이트로 되돌림(네 번 모두 해시 같음). 창 기억 파일은 "기억 없음" 으로 되돌림.
|
||
- 확인 값은 git 과 커밋 blob 바이트로 읽었다. 결과 커밋의 파일마다 BOM · CRLF · LF · UTF-8 을 첫 부모와 견주고, 충돌 표식을 찾고,
|
||
**`UnitN.cs` 안의 class 이름이 `UnitN` 인지**도 봤다(아래 N1 을 찾은 뒤 더한 검사).
|
||
|
||
### 네 길의 결과
|
||
|
||
| 확인 | ① 병합 | ② pull | ③ rebase | ④ cherry-pick |
|
||
|---|---|---|---|---|
|
||
| 시작 | [Merge → 현재 브랜치로] | 원격 [펴기] → [Pull] | [선택 브랜치 위로 rebase] | 이력 [모든 브랜치] → `상대 쪽 작업` [Cherry-pick] |
|
||
| 알림 | 충돌 24건 (머지 주석만 다른 2건은 자동으로 풀림) … | 같음 | 같음 + "다 풀면 [계속] 으로 rebase 를 이어 갑니다" | 같음 + "다 풀면 [커밋] 으로 cherry-pick 을 끝냅니다" |
|
||
| 머리 표시 · 진행 줄 | 병합 진행 중 · 남은 충돌 24개 · 푼 것 2개 (2/26) | 같음 | rebase 1/1 · 남은 충돌 24개 | cherry-pick 진행 중 · 남은 충돌 24개 |
|
||
| 파일 단위 Accept Theirs 15개 | 24 → 9, 1.0초 | 같음 | 같음 | 같음 |
|
||
| Accept Both | 먼저 묻는다 · [아니오] → git 그대로 `AA` | 같음 | 같음 | 같음 |
|
||
| 충돌 남은 채 Save & Commit | 눌림 · git 그대로 · 커밋 없음 | 같음 | 꺼져 있음 | 꺼져 있음 |
|
||
| 네 칸 REMOTE 제목 | `REMOTE · feature/theirs` | 같음 | `REMOTE · 다시 올리는 내 커밋 bf67020 내 쪽 작업` | `REMOTE · 가져오는 커밋 7fac93b 상대 쪽 작업` |
|
||
| 네 칸 머리 글 | 병합 충돌 · REMOTE = feature/theirs | 같음 | rebase 충돌 · LOCAL = 올릴 자리 feature/theirs · REMOTE = 다시 올리는 내 커밋 bf67020 | cherry-pick 충돌 · REMOTE = 가져오는 커밋 7fac93b |
|
||
| 3분할로 푼 파일(앱이 연 순서) | NewPanel · Unit47 · 한글설명 · LineEnding · Unit0(6) · 띠 둘 · View250 · Unit1(6) | 같음 | 같음 | 같음 |
|
||
| 줄 고른 로그 | 18줄 · `Theirs(feature/theirs)` · `Mine(feature/mine)` | 같음 | 18줄 · `Theirs(커밋 bf67020)` · `Mine(feature/theirs)` | 18줄 · `Theirs(커밋 7fac93b)` · `Mine(feature/mine)` |
|
||
| 마지막 Save 뒤 파일 비교 탭 | **충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 3줄** · `… · 병합 전 내 쪽` | 같음 | **`2680b84 · Weld/Unit1.cs` · 남은 차이 3줄** (N2) | **`ecb7e47 · Weld/Unit1.cs` · 남은 차이 3줄** (N2) |
|
||
| 다 푼 뒤 충돌 탭 | 충돌 정리 끝 · 푼 것 26개 - 병합 커밋을 할 수 있습니다 · [병합 커밋] 켜짐 | 같음 · 메시지 칸 `Merge remote-tracking branch 'origin/feature/mine' into feature/mine` | 충돌 정리 끝 - [계속] 으로 rebase 를 이어 갑니다 · [계속] 켜짐 | 충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다 · [커밋] 켜짐 |
|
||
| 끝낸 커밋 | `fce391f` 부모 둘 · `Merge branch 'feature/theirs' into feature/mine` · 본문 없음 | `c70884c` 부모 둘 · `Merge remote-tracking branch 'origin/feature/mine' into feature/mine` | `rebase 완료 (1/1 단계)` · `e0302c2 내 쪽 작업` ← `2680b84 상대 쪽 작업` ← 바탕 | `17bbf0b` 부모 하나 · `상대 쪽 작업`(원래 메시지) |
|
||
| 줄끝 · BOM · 인코딩이 첫 부모와 다른 파일 | **0 / 33** | **0 / 33** | **0 / 31** | **0 / 33** |
|
||
| 충돌 표식 · class 이름이 다른 Unit 파일 | 0 · 0 | 0 · 0 | 0 · 0 | 0 · 0 |
|
||
| 끝난 뒤 | 워킹트리 Clean · 진행 표시 · [작업 취소] 사라짐 · `.git` 에 MERGE_HEAD · MERGEHUB_CONFLICTS 없음 | 같음 | 같음 · rebase-merge 없음 | 같음 · CHERRY_PICK_HEAD 없음 |
|
||
|
||
### 판정 기준
|
||
|
||
| 기준 | 결과 |
|
||
|---|---|
|
||
| 네 길 모두 MergeHub 만으로 커밋(또는 rebase 끝)까지 | **됐다.** 터미널 git 은 저장소 · 원격 준비와 결과 확인에만 썼다 |
|
||
| 줄끝 · BOM 이 바뀐 파일 0개 | **0.** 네 길 모두 |
|
||
| A-1 이 다시 나지 않는다 | **병합 · pull 은 안 났다. rebase · cherry-pick 에서는 같은 증상이 난다**(N2) — A-1 은 "병합 중" 일 때만 말을 바꾸도록 고쳤다 |
|
||
| A-2 가 다시 나지 않는다 | **안 났다.** 네 길 로그 72줄에 "3-Way 안 씀" 0, 네 칸 머리에 3-Way 콤보 없음 |
|
||
| B-1 이 다시 나지 않는다 | **안 났다.** 병합 커밋 · pull 병합 커밋 뒤 `.git/MERGEHUB_CONFLICTS` 없음 |
|
||
| #12 MERGED 칸 줄 번호 (`Motion/Unit0.cs` · `Weld/Unit1.cs` 끝 줄) | **잘리지 않는다.** 네 칸 화면에서 이동 칸에 끝 줄 번호를 넣고 찍음 — 3346 ~ 3363, 3770 ~ 3787 네 자리가 다 보인다. 다만 번호가 결과 파일 번호와 다르다(N3) |
|
||
|
||
### 새로 걸린 것 (고치지 않음 → 8차)
|
||
|
||
| # | 무엇 | 근거 |
|
||
|---|---|---|
|
||
| **N1** | **고른 충돌 파일 대신 다른 파일이 보이고, 그 화면을 [Save] 하면 고른 파일에 써진다.** 파일 비교 탭을 한 번도 열지 않은 채 충돌 탭에서 파일을 고르고 [3분할로 열기] 를 누르면 화면은 첫 충돌 파일(`Common/Util/Unit15.cs`)을 보인다. 거기서 Take Theirs → [Save] 하자 **`Common/Util/Unit47.cs` 가 Unit15 의 내용(123줄 · `class Unit15` · 고른 줄 · 머지 주석)으로 스테이징**됐고, Unit15 는 그대로 `UU`. 로그는 "충돌 해결(직접 편집 …): Common/Util/Unit47.cs". 화면은 30초 동안 Unit15 · "남은 충돌 1개" 그대로 | 병합 · pull 둘 다 같은 순서로 다시 났다(스크린샷 · 스테이징된 blob). 파일 비교 탭을 먼저 한 번 열어 두면 안 난다 — 네 길 확인은 그렇게 했다. 짚이는 곳: 탭이 처음 만들어질 때의 목록 세우기(첫 파일 로드)와 `OpenConflictAsync`(고른 파일)가 겹친다. `LoadFileAsync` 는 늦게 끝난 로드를 `IsGitMode` 로만 버리고 **읽는 사이 고른 파일이 바뀌었는지는 보지 않는다**(`HomeViewModel.cs:1291`). 코드를 읽어 짚은 것이라 원인은 확정하지 않았다. **남의 파일을 조용히 덮어쓰므로 8차에서 가장 먼저** |
|
||
| N2 | rebase · cherry-pick 에서 마지막 [Save] 뒤 파일 비교 탭이 두 칸으로 떨어져 **"남은 차이 3줄"** 을 보인다. 충돌 탭은 "충돌 정리 끝 - [계속] (또는 [커밋]) …" 이라 두 화면이 다른 말을 한다 — A-1 과 같은 증상 | `Weld/Unit1.cs` 저장 직후. A-1 의 `ResolvedMergeSummary` · "병합 전 내 쪽" 은 `IsMergeInProgress`(병합 표시) 일 때만 쓰인다 |
|
||
| N3 | MERGED 칸 줄 번호가 **결과 파일 번호가 아니라 원래 내 쪽 번호로 보인다.** `Motion/Unit0.cs` 는 고른 줄 · 주석으로 3줄이 늘어 상태바는 "3366행 · 총 3366줄" 인데 MERGED 칸 끝 번호는 3363 이고 줄마다 LOCAL 칸과 같은 번호 | 네 칸 스크린샷. MERGED 칸 번호는 `LocalNumberText`(정렬 때 정한 번호)라 편집 뒤 다시 매기지 않는 것으로 보인다. 설계일 수도 있어 8차에서 정한다 |
|
||
| N4 | 바뀌는 것 없는 cherry-pick(HEAD 커밋을 다시)에서 **[커밋] 이 켜지고, 누르면 로그에만 "[cherry-pick 커밋] 실패: No changes; nothing to commit."** 이 남는다. 진행 표시 · 진행 줄 "충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다" 가 그대로라 같은 단추를 또 누르게 된다. [작업 취소] 로는 빠져나온다 | C-2 에서 적어 둔 것을 다시 봤다. 알림 문장은 자동 조작이 못 읽었다 |
|
||
|
||
### 확인하며 알게 된 것 (제품 결함 아님)
|
||
|
||
- **사용자 이름 창.** 켤 때마다 뜨는 이름 창(플랫폼 E-3)이 떠 있어도 UI 자동화는 뒤의 본 창 단추를 누를 수 있다. 첫 병합 확인은 창을 닫지 않은 채 돌아 **사람이 갈 수 없는 길**이었다. 창을 [저장] 으로 닫고 병합을 다시 했다(위 표 ①). 사람의 마우스 · 키보드는 막히므로 E-3 결함은 아니다.
|
||
- **Pull 단추**는 접힌 원격 영역 안에 있다(설정 `GitRemoteExpanded` 꺼짐). 첫 pull 확인은 단추를 못 찾아 멈췄다 — 사람처럼 [▸ 원격 저장소 · 계정 펴기] 를 누르게 했다.
|
||
- 한 번 멈춘 pull 확인에서 N1 을 처음 봤다. 그때 [Save] 가 Unit47 을 Unit15 내용으로 덮었고, 끝낼 수 없어 그 저장소는 버렸다.
|
||
- 줄끝 검사는 N1 같은 **내용 뒤바뀜을 못 잡는다**(Unit15 · Unit47 둘 다 BOM · CRLF). 이번부터 class 이름 검사를 더했다.
|
||
- `Recipe/ToBeDeletedByMe.cs` 를 남기면 git 상태가 `R`(이름 바뀜)로 읽힌다 — 같은 크기의 `ToBeDeleted.cs` 를 지운 것과 짝지어 보는 git 의 이름 추적이다. 커밋 결과는 각각 지움 · 남김으로 맞다.
|
||
- 결과 확인 스크립트가 부모 하나인 커밋(rebase · cherry-pick)에서 merge-base 오류를 냈지만 줄끝 판정은 첫 부모와 제대로 했다.
|
||
|
||
코드는 바꾸지 않았으므로 검사는 그대로 · 빌드 경고 0 · 오류 0.
|
||
|
||
## E-4. 창 크기를 마음대로 조절할 수 있게 (2026-09-15, 추가 요청, 완료 · 플랫폼)
|
||
|
||
사용자: "현재는 화면크기 최대화만 지원인데 이거 크기를 마음대로 조절할수있게 할수있겠어?" — 하는 중에 두 가지를 더 정했다.
|
||
- "화면크기 최대화하면 작업표시줄 안보이게 화면을 채워줘" → 지시서의 "작업 표시줄을 덮지 않는다" 를 **덮는다** 로 바꿈.
|
||
- "화면 크기를 조절할때 엄청 깜빡거려 깜빡거리지 않게 해줘" → 깜빡임 없애기를 기준에 더함.
|
||
|
||
고친 곳은 모두 **플랫폼 셸 창**(`UbisamBase.Core/Shell`)이다. MergeHub 코드는 바꾸지 않았다.
|
||
|
||
### 고치기 전에 쟀다 (2560×1600@150% · 1920×1080@100% 두 모니터)
|
||
|
||
| 확인 | 결과 |
|
||
|---|---|
|
||
| 켠 직후 | 최대화 2560×1600, 크기 조절 테두리(WS_THICKFRAME) **없음** |
|
||
| 브랜딩 바 두 번 누르기 | 아무 일 없음 |
|
||
| 브랜딩 바 끌기 | 끄는 동안 1792×1069 로 줄었다가 **놓으면 다시 최대화** |
|
||
| Win+↓ | 2560×1528 "보통" 창 — 작업 영역만 하고 크기를 바꿀 수 없음 |
|
||
|
||
### 고친 것 (플랫폼)
|
||
|
||
| 파일 | 무엇 |
|
||
|---|---|
|
||
| `Shell/ShellWindow.xaml` | `ResizeMode=CanResize` · 최소 1280×720 · `WindowChrome`(끌어 크기 조절 테두리 6px, 제목 영역 0, 유리 틀 아래 1px) · 브랜딩 바 끌기 처리기 |
|
||
| `Shell/ShellWindow.xaml.cs` | 두 번 누르기 = 최대화 ↔ 복원 · 보통 크기에서 끌면 크기 그대로 옮김(놓아도 다시 최대화하지 않음) · 최대화에서 끌면 **실제로 움직일 때** 복원 크기로 줄여 따라옴 · 화면 이동은 보통 크기면 DIP 크기와 상대 위치를 지키고 최대화면 그 모니터를 채움 · Win+↓ 로 작업 영역만 한 창이 남으면 복원 크기로 · 마지막 크기 · 위치 · 최대화 여부 기억(창을 보이기 전에 복원) · **최대화 동안 크기 조절 틀을 떼고** 보통 크기로 돌아오면 다시 붙임 · 창 그리기 바탕을 앱 배경색으로 |
|
||
| `Shell/MonitorLayout.cs` | 창 사각형 읽기 · `WM_GETMINMAXINFO` — 최대화 = 그 모니터 전체(작업 표시줄 포함), 최대 끌기 크기도 그 모니터로, 최소 끌기 크기 |
|
||
| `Shell/WindowPlacementMath.cs` (새 파일) | 최소 크기(화면이 작으면 작업 영역에 맞춤) · 복원 크기(기억 없으면 작업 영역 80%) · 커서 아래로 줄이기 · 모니터 사이 옮기기(배율 비) · 작업 영역 안으로 · 작업 영역을 덮는지 · 기억한 자리가 지금 모니터에 보이는지 |
|
||
| `Shell/ShellWindowPlacement.cs` (새 파일) | `{설정 폴더}\ShellWindowPlacement.json` — UI 설정 파일과 따로(그쪽은 [저장] 을 눌러야 씀) |
|
||
| `Settings/UiSettingsService.cs` | `SettingsDirectory` |
|
||
| 하네스 `PlacementTest` (새로 만듦) | 계산 · 기억 파일 검사 37건 |
|
||
|
||
### 확인하며 찾아 고친 것
|
||
|
||
| # | 무엇 | 어떻게 알았나 · 고침 |
|
||
|---|---|---|
|
||
| 1 | **최대화하면 작업 표시줄이 창 위에 떠 하단 탭 바를 가림** — [화면 이동] · [종료] 가 안 눌림(사용자도 지적) | 그 자리의 창이 `Shell_TrayWnd`. 예전 셸과 창 크기 · 스타일 비트가 **같았고**, 다른 것은 크기 조절 틀(WindowChrome) 하나였다. 최대화 중 테두리만 떼기 · 작업 표시줄에 전체 화면이라고 알리기(`MarkFullscreenWindow`)는 효과가 없어 되돌렸고, **최대화 동안 틀을 떼자** 두 모니터 모두 앱 창이 받았다 |
|
||
| 2 | **크기를 바꿀 때 창이 통째로 검게 깜빡임**(사용자 지적) | 오른쪽 가장자리를 끄는 동안 40장 찍어 검은 픽셀 비율: 고치기 전 **최대 99.7%** → 창 그리기 바탕을 앱 배경색으로 + 유리 틀 1px → **최대 3.0%(파일 비교) · 2.0%(폴더 비교), 절반 넘게 검은 장 0**. 끌지 않을 때는 0% |
|
||
| 3 | 기억한 보통 크기로 켰는데 Windows 는 "최대화" 로 봄 | XAML 의 최대화가 복원보다 늦게 걸림 → 창을 보이기 전(생성자)에 보통 상태로 정함 |
|
||
| 4 | 보통 크기로 한 번도 안 쓰고 옆 모니터에서 최대화로 끄면 다음에 주 모니터로 켜짐 | 그 모니터의 복원 자리를 함께 기억 |
|
||
| 5 | 최대화로 넘어가는 순간의 모니터만 한 크기가 "보통 크기" 로 기억됨 | 작업 영역을 거의 덮는 크기는 기억하지 않음 |
|
||
| - | (측정 쪽) 옆 모니터 창이 1.5배 크게 재짐 | 앱은 모니터별 배율 인식(2)인데 측정한 PowerShell 이 시스템 배율(1)이라 좌표가 부풀려졌다. 측정 스레드를 모니터별 배율로 바꿔 다시 쟀다 |
|
||
|
||
### 확인한 것 (실제 픽셀, 배포 전 앱 폴더에 새 Core 를 넣어서)
|
||
|
||
| 확인 | 결과 |
|
||
|---|---|
|
||
| 켠 직후(기억 없음) | 최대화 2560×1600 = 모니터 전체 · 테두리 없음 · 하단 바를 앱 창이 받음 |
|
||
| 두 번 누르기 | 보통 2048×1222(작업 영역 80%, 가운데) ↔ 최대화 |
|
||
| 가장자리 · 모서리 끌기 | 가로 1920px · 세로 1080px(= **1280×720 DIP**)에서 멈춤 · 모서리로 키우기 됨 |
|
||
| 보통 크기에서 브랜딩 바 끌기 | **크기 그대로** 자리만 옮김, 보통 크기 유지 |
|
||
| 최대화에서 한 번 누르기 · 끌기 | 한 번 누르기는 그대로 · 끌면 2048×1222 로 줄어 따라오고 보통 크기로 남음 |
|
||
| Win+↑ · Win+↓ | 모니터 전체로 최대화 ↔ 기억한 보통 크기. 옆 모니터에서 Win+↑ = 1920×1080 전체 |
|
||
| 화면 이동(보통) 20번 | 150% 2048×1222px ↔ 100% 1365×815px, **DIP 1365×815 로 20번 모두 같음** |
|
||
| 화면 이동(최대화) | 주 ↔ 옆 모니터 전체로 옮김, 하단 바를 앱 창이 받음 |
|
||
| 보통 크기로 [종료] → 다시 켬 | 같은 자리 · 크기, 최대화 아님 |
|
||
| 옆 모니터 최대화로 [종료] → 다시 켬 | 옆 모니터(2560,0 1920×1080)에서 최대화 |
|
||
| 보통 크기로 내리면 | 작업 표시줄이 다시 보이고 테두리가 붙음 |
|
||
| MergeHub 네 탭 · 최소 1280×720 DIP | 폴더 비교 · 파일 비교 네 칸 · Git 충돌 · 설정 모두 **잘리지 않음**. 파일 비교 머리의 [새로고침] 과 폴더 비교 [비교] · [결과 닫기] 가 다음 줄로 접히고, ACTIONS 칸 · 충돌 목록은 스크롤 |
|
||
| MergeHub 네 탭 · 옆 모니터 최대화 1920×1080 | 모두 잘리지 않음 |
|
||
|
||
사용자 확인 뒤 `publish-platform.ps1` 로 `D:\UbisamPlatform\bin` 배포(Core · Shell Release 경고 0 · 오류 0, 파일 48 · pdb 0), MergeHub 다시 빌드(경고 0 · 오류 0, 앱 폴더 Core = 배포본). 배포본으로 켜 최대화 · 하단 바 · 두 번 누르기 · [종료] 다시 확인.
|
||
설정 폴더: 시험마다 기억 파일을 "기억 없음"(크기 0 · 최대화)으로 되돌림, 다른 설정 파일은 그대로(해시).
|
||
|
||
### 남긴 것
|
||
|
||
- 기억이 없을 때 **처음 Win+↓** 는 XAML 기본 크기(1600×900 DIP)로 내려온다. 두 번 누르기는 작업 영역 80%. 둘 다 쓸 수 있는 크기라 맞추지 않았다.
|
||
- 보통 크기 창 가장자리에 Windows 기본 테두리 선이 1px 보인다(유리 틀 1px).
|
||
- 창 끌어 스냅(화면 왼쪽 · 오른쪽 반쪽)은 따로 재지 않았다.
|
||
- **모든 소비 프로그램에 영향** — 플랫폼 changelog 에 적었다. 처음 켜면 지금처럼 최대화로 작업 표시줄을 덮으므로 크기를 안 바꾸는 사람에게는 같다.
|
||
|
||
## E-2. 폴더 비교 탭에 폴더를 하나씩 끌어다 놓으면 첫 칸 → 둘째 칸 차례로 (2026-09-14, 추가 요청, 완료)
|
||
|
||
사용자: "폴더비교 탭 첫번째 드래그 첫번째 폴더 경로에 들어가고 두번째는 드래그앤드롭은 두번째로 들어가게해줘 경로텍스트 박스에 안넣어도 그냥 화면에다 넣어둬 기능 동작하도록".
|
||
|
||
### 원인 (코드로 확인)
|
||
|
||
- 화면 아무 데나 놓으면 `FolderView.View_Drop` → `GitWorkspace.RouteDroppedPaths` → `RequestFolderCompare(왼쪽, null)`. **폴더 하나는 늘 첫 칸**으로 갔다.
|
||
두 번째 폴더를 놓아도 첫 칸을 덮어써서, 경로 칸 위에 정확히 놓지 않으면 두 폴더를 견줄 수 없었다.
|
||
- 경로 칸 위에 놓는 길(`PreviewDrop` → `DropIntoSlot`)은 그 칸에 제대로 들어갔다.
|
||
- 고치기 전 모습은 화면으로 따로 찍지 않았다 — 위 경로를 코드로 따라가 확인했다.
|
||
|
||
### 고친 것
|
||
|
||
| 파일 | 무엇 |
|
||
|---|---|
|
||
| `Services/DropSlotOrder.cs` (새 파일) | 놓는 차례. `Take()` 는 첫 칸 → 둘째 칸 → 첫 칸 … 을 주고, `Placed(칸)` 은 칸에 바로 놓은 것도 차례에 쳐서 다음을 반대 칸으로 |
|
||
| `Views/FolderView.xaml.cs` | 화면에 **폴더 하나**를 놓으면 `DropFolder(폴더, 차례 칸)` — 양쪽이 차면 바로 견준다(원래 있던 동작). 경로 칸 위에 놓으면 그 칸에 넣고 차례를 넘김(두 개를 한꺼번에 놓아 양쪽을 채웠으면 다음은 첫 칸). 두 개 · 파일을 놓는 길은 그대로(명령줄과 같은 판단) |
|
||
| 하네스 `PathTest` | 차례 검사 8건 |
|
||
|
||
### 확인한 것 (실제 탐색기 창에서 마우스로 끌어다 놓기)
|
||
|
||
경로 칸을 비우고, 탐색기에서 폴더를 끌어 **폴더 비교 화면의 빈 곳**(경로 칸이 아닌 곳)에 놓았다.
|
||
|
||
| # | 놓은 것 · 자리 | 첫 칸 | 둘째 칸 |
|
||
|---|---|---|---|
|
||
| 1 | `왼쪽폴더` · 화면 | **왼쪽폴더** | (빔) |
|
||
| 2 | `오른쪽폴더` · 화면 | 왼쪽폴더 | **오른쪽폴더** — 바로 비교, 결과에 `a.txt` |
|
||
| 3 | `세번째폴더` · 화면 | **세번째폴더** | 오른쪽폴더 |
|
||
| 4 | `왼쪽폴더` · **둘째 경로 칸 위** | 세번째폴더 | **왼쪽폴더** |
|
||
| 5 | `오른쪽폴더` · 화면 (차례: 첫 칸) | **오른쪽폴더** | 왼쪽폴더 |
|
||
|
||
PathTest 62건 통과. 빌드 경고 0 · 오류 0.
|
||
|
||
## E-3. 사용자 이름을 저장하기 전에는 화면을 쓸 수 없게 (2026-09-14, 추가 요청, 완료)
|
||
|
||
사용자: "사용자 이름을 저장하고 화면이 움직이거나 바뀌도록 잠궈야해". 저장해야만 화면을 움직이거나 바꿀 수 있게 잠근다고 읽었다.
|
||
켤 때 뜨는 이름 창은 **플랫폼**(`UbisamBase.Core/Settings/UserNameDialog`)의 것이다.
|
||
|
||
### 고치기 전에 쟀다 (켤 때 이름 창)
|
||
|
||
| 확인 | 결과 |
|
||
|---|---|
|
||
| 이름 창 주인 · 본 창 | 주인이 본 창, 본 창 입력 막힘 — 여기까지는 됐다 |
|
||
| 제목줄을 끌기 | **이름 창이 움직였다** (663,377 → 863,477) |
|
||
| 저장 없이 닫기(WM_CLOSE, Alt+F4 와 같은 길) | **이름 창이 닫히고 본 창을 그대로 쓸 수 있었다** — 설정 탭으로 옮겨짐. 이름은 안 받음 |
|
||
| 설정 폴더 | 바뀐 것 없음 |
|
||
|
||
### 고친 것 (플랫폼)
|
||
|
||
| 파일 | 무엇 |
|
||
|---|---|
|
||
| `UbisamBase.Core/Settings/UserNameDialog.xaml.cs` | `OnClosing` 에서 저장 전이면 닫기를 막고 "이름을 저장해야 시작합니다." 를 보인 뒤 이름 칸으로 포커스. 저장하면 닫힌다. 제목줄 끌어 옮기기(`DragMove`) 뺌 |
|
||
| `UbisamBase.Core/Settings/UserNameDialog.xaml` | 제목줄의 끌기 처리기 뺌 |
|
||
|
||
플랫폼 규칙대로 사용자 확인을 받고 `scripts\publish-platform.ps1` 로 `D:\UbisamPlatform\bin` 을 갱신했다(Core Release 경고 0 · 오류 0, 파일 48 · pdb 0).
|
||
MergeHub 는 빌드 때 그 폴더를 통째로 복사하므로 다시 빌드해 앱 폴더의 Core 에 새 문구가 들어간 것을 확인했다.
|
||
그 폴더를 쓰는 다른 소비 프로그램(UbisamBase.App · TestApp 등)도 다시 빌드하면 같은 잠금을 받는다 — 플랫폼 changelog 에 적었다.
|
||
|
||
### 확인한 것 (새 Core 로 앱을 켜서)
|
||
|
||
| 확인 | 결과 |
|
||
|---|---|
|
||
| 제목줄 끌기 | **움직이지 않음** |
|
||
| 저장 없이 닫기(WM_CLOSE) | **이름 창 그대로 · 본 창 입력 막힘 그대로**, 창에 "이름을 저장해야 시작합니다." |
|
||
| [저장] | 이름 창 닫힘 · 본 창 입력 가능 · 탭 옮기기 됨 |
|
||
| 설정 폴더 | 그날 로그 파일 말고 바뀐 것 없음(같은 이름으로 저장) |
|
||
|
||
MergeHub 코드는 바꾸지 않았다. 빌드 경고 0 · 오류 0.
|
||
|
||
## E-1. [해결로 저장] 이름을 [Save] 로 (2026-09-14, 추가 요청, 완료)
|
||
|
||
사용자: "해결로 저장은 LOCAL SAVE 버튼이잖아? 그냥 Save 로 이름 바꿔주고".
|
||
병합 중에만 보이는 그 단추는 LOCAL 칸 내용을 이 파일에만 쓰고 스테이징한다. 바로 아래 Save & Commit 과 짝이 되게 이름만 바꿨다. 하는 일은 그대로다.
|
||
|
||
### 바꾼 것
|
||
|
||
| 파일 | 무엇 |
|
||
|---|---|
|
||
| `Views/HomeView.xaml` | 단추 글자 `해결로 저장` → `Save` (툴팁 "이 파일만 풀어서 저장하고 스테이징합니다. 커밋은 하지 않습니다 (Ctrl+S)" 그대로) |
|
||
| `ViewModels/HomeViewModel.cs` | 작업 이름(`RunAsync`) · 알림 `Save · 파일 · 남은 충돌 N건` / `… 남은 충돌 없음 - 이제 커밋할 수 있습니다` |
|
||
| `Services/MergeSavePlan.cs` | Save & Commit 이 막힐 때 안내 "[Save] 로 이 파일만 저장해 두고 …" |
|
||
| `doc/web/index.html` | 매뉴얼 · 단축키 · 한계 · 시연 대본 · 비교표의 이름 |
|
||
|
||
지난 기록(history · 6차 지시서)은 그때 이름 그대로 두었다. 코드 주석의 옛 이름도 그 시점 설명이라 두었다.
|
||
|
||
### 확인한 것 (새로 만든 저장소, MergeHub 로 병합한 뒤)
|
||
|
||
| 확인 | 결과 |
|
||
|---|---|
|
||
| 병합 중 네 칸의 단추 | **Save** · 옆에 Save & Commit. "해결로 저장" 단추 없음 · 화면 전체 글자에도 없음 |
|
||
| `Io/Unit12.cs` 충돌 1개 Take Theirs → [Save] | 알림 **"Save · Unit12.cs · 남은 충돌 23건"**. git 충돌 24 → 23, 파일 `M ` 스테이징, HEAD 그대로(커밋 없음) |
|
||
| 저장 뒤 | 남은 충돌 첫 파일(`Common/Util/Unit15.cs`)이 네 칸으로 열림 |
|
||
|
||
빌드 경고 0 · 오류 0.
|
||
|
||
**바로잡음 (A-1 때 발견)** — 처음에 "하네스는 이 파일들을 컴파일하지 않아 그대로" 라고 적었는데 틀렸다.
|
||
`MergeSaveTest` 가 `MergeSavePlan.cs` 를 컴파일하고, 막힘 안내에 "해결로 저장" 이 들어 있는지 보고 있었다.
|
||
찾을 때 하네스 폴더를 빠뜨렸고 하네스를 돌리지 않았다. A-1 에서 기대값을 `[Save]` 로 고치고 "옛 이름이 없다" 검사를 더했다.
|
||
설정 파일은 백업 → `CSharpBraceStyle` 끔 → 시험 → 바이트 그대로 되돌림(해시 같음).
|
||
|
||
(자동 조작 쪽: 앱을 새로 켠 뒤에는 충돌 목록에 고른 것이 없어 [3분할로 열기] 가 아무것도 안 열었다. 목록에서 파일을 고르고 다시 했다.)
|