충돌 탭 파일 단위 Accept 는 소스에 주석이 안 남고, 병합 커밋 본문은 비어 있었고, Git 탭 로그는 끄면 사라져 누가 어느 파일을 어떻게 풀었는지 남는 곳이 없었다(사용자 요청). - MergeResolutionLog: 기록 파일(첫 줄 MERGE_HEAD) 읽기 · 쓰기, 본문 만들기, 메시지에 붙이기 - GitService: 병합 중일 때만 .git/MERGEHUB_RESOLUTIONS 에 적고, CommitMerge 가 본문을 붙인다. 병합 커밋 · 작업 취소 · 새로고침 때 쓸모없는 기록을 치운다 - 충돌 탭 Accept Mine/Theirs/Both · [Save] · Save & Commit · 파일 남기기/지우기 · 머지 주석 자동이 적는다 - Git 탭 메시지 칸에 본문을 미리 채우고, 풀 때마다 새로 채운다(사람이 고치면 두고 커밋 때 붙임) - 하네스 MergeSaveTest 183건(21건 추가), 22벌 1,094건 통과 확인: 병합 "충돌 해결 26개 · 김승준"(줄 단위 7 · Theirs 15 · 남기기 1 · 지우기 1 · 주석 자동 2), pull 26개, Accept Mine 기록 뒤 [작업 취소] 로 기록 파일 없음. 줄끝 · BOM 0/33, 회귀 없음. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
198 lines
17 KiB
Markdown
198 lines
17 KiB
Markdown
# 작업 지시 — MergeHub 8차 (고른 파일에 고른 내용을 · 작업마다 화면이 사실대로)
|
||
|
||
대상: `D:\Sorce\MergeTool\MergeHub` (플러그인) · `D:\Sorce\MergeTool\UbisamPlatform` (셸)
|
||
전제: 1~7차 지시서는 모두 끝났다([../진행상황.md](../진행상황.md)).
|
||
|
||
**이번 지시서가 나온 곳** — 7차 D-1 에서 시험 저장소를 길마다 새로 만들어 **병합 · pull · rebase · cherry-pick** 을 MergeHub 만으로 끝까지 했다.
|
||
네 길 모두 커밋까지 갔고 줄끝 · BOM 이 바뀐 파일은 0 이었다. 대신 **새로 걸린 것이 넷**이고,
|
||
그중 하나(N1)는 **고른 파일에 다른 파일의 내용을 써 버린다.** 근거와 수치는 [../history/2026-09-14-7차.md](../history/2026-09-14-7차.md) 의 D-1 에 있다.
|
||
|
||
| 7차 D-1 에서 잰 것 | 병합 | pull | rebase | cherry-pick |
|
||
|---|---|---|---|---|
|
||
| 끝낸 커밋 | 부모 둘 | 부모 둘 | rebase 완료 1/1 | 부모 하나 · 원래 메시지 |
|
||
| 줄끝 · BOM 이 바뀐 파일 | 0 / 33 | 0 / 33 | 0 / 31 | 0 / 33 |
|
||
| 마지막 Save 뒤 파일 비교 탭 | 충돌 정리 끝 | 충돌 정리 끝 | **남은 차이 3줄** | **남은 차이 3줄** |
|
||
| A-2 · B-1 | 안 남 | 안 남 | 안 남 | 안 남 |
|
||
|
||
---
|
||
|
||
## 공통 규칙
|
||
|
||
- **A → B → C → D → E 순서로 진행한다.** A 는 사용자의 파일을 망가뜨리는 것이라 무엇보다 먼저다.
|
||
- **항목 하나를 끝낼 때마다** 빌드하고 실제로 실행해 화면을 확인한 뒤 보고한다.
|
||
- **항목 하나가 끝나면 기록을 세 군데에 남기고 로컬 커밋한다**(4차 D-2 규칙).
|
||
1. **상세**는 `doc/history/YYYY-MM-DD-8차.md` — 원인 · 판단 · 확인한 결과
|
||
2. [../진행상황.md](../진행상황.md) 은 **대기 → 완료로 상태만**
|
||
3. [../history/changelog.md](../history/changelog.md) 에 한 줄 — 날짜 · 무엇을 왜 · 커밋
|
||
- **푸쉬하지 않는다.**
|
||
- **실제 소스를 열지 않는다**(2026-09-11 결정). 시험 재료는 `C1Repo` 로 만든 저장소로 한다. 씨앗이 고정돼 몇 번을 만들어도 같다.
|
||
고치기 전에 문제가 **다시 나는 것부터 보이고**, 고친 뒤 안 나는 것을 보인다.
|
||
- 기존 검사 하네스는 계속 통과해야 한다. 로직을 건드리면 **테스트를 먼저 늘린다.**
|
||
- 빌드 경고 0 · 오류 0 을 유지한다. 앱이 실행 중이면 `UbisamBase.Shell` 을 먼저 종료한다.
|
||
- 사용자 설정 파일(`D:\UbisamConfig\Settings\MergeHubSettings.json`)은 시험 전에 백업하고, 끝나면 **바이트 그대로** 되돌린다.
|
||
창 기억(`ShellWindowPlacement.json`)은 시험 뒤 "기억 없음" 으로 둔다.
|
||
- **자동 조작으로 확인할 때는 사람이 갈 수 있는 길만 쓴다**(7차 D-1 에서 배움).
|
||
켤 때 뜨는 사용자 이름 창을 먼저 [저장] 으로 닫는다 — UI 자동화는 떠 있는 창 뒤의 단추도 누를 수 있다.
|
||
접힌 영역(원격 · Pull)은 사람처럼 펴고 누른다.
|
||
- **결과 확인은 줄끝만 보지 않는다.** 커밋된 `UnitN.cs` 안의 class 이름이 `UnitN` 인지(내용이 다른 파일로 뒤바뀌지 않았는지)도 본다.
|
||
- 플랫폼을 고치면 다른 소비 프로그램에 미치는 영향을 함께 적고 `UbisamPlatform/doc/history/changelog.md` 에 남긴다. **배포는 사용자 확인 뒤.**
|
||
|
||
---
|
||
|
||
## A. 사용자의 파일을 망가뜨리는 것
|
||
|
||
### A-1. 고른 충돌 파일 대신 다른 파일이 보이고, 그 화면을 저장하면 고른 파일에 써진다 (7차 D-1 N1)
|
||
|
||
- **다시 내는 순서**(병합 · pull 둘 다 났다):
|
||
1. 새 저장소를 열고 [Merge → 현재 브랜치로](또는 Pull). **파일 비교 탭은 한 번도 열지 않는다.**
|
||
2. Git 탭 충돌 목록에서 `Common/Util/Unit47.cs` 를 고르고 [3분할로 열기].
|
||
3. 파일 비교 탭이 열리는데 **파일 콤보 · 칸 제목 · 내용이 첫 충돌 파일 `Common/Util/Unit15.cs`** 다.
|
||
4. [다음 충돌] → Take Theirs → [Save].
|
||
5. **`Common/Util/Unit47.cs` 가 Unit15 의 내용(123줄 · `class Unit15` · 고른 줄 · 머지 주석)으로 스테이징**되고 Unit15 는 `UU` 그대로.
|
||
로그 "충돌 해결(직접 편집 …): Common/Util/Unit47.cs". 화면은 30초 동안 Unit15 · "남은 충돌 1개" 그대로다.
|
||
- 파일 비교 탭을 **먼저 한 번 열어 두면 안 난다.** 7차 D-1 네 길은 그렇게 해서 끝까지 갔다.
|
||
- 짚이는 곳(코드를 읽어 짚은 것 — 원인부터 확인할 것):
|
||
- 파일 비교 화면은 탭을 처음 열 때 만들어진다. 그때 목록 세우기(`RebuildListAfterRefreshAsync` → `LoadCommitAsync` → 첫 파일 `LoadFileAsync`)와
|
||
넘겨받은 요청(`DeliverPendingOpenConflict` → `OpenConflictAsync` → `SelectedFile = Unit47`)이 겹친다.
|
||
- `LoadFileAsync` 는 늦게 끝난 로드를 `IsGitMode` 로만 버린다(`HomeViewModel.cs` "읽어 오는 사이에 파일 비교 모드로 넘어갔으면 버린다").
|
||
**읽기 시작한 경로가 지금 고른 파일과 같은지는 보지 않는다.** 같은 주석이 "경로는 새 파일인데 내용은 옛 파일인 상태" 를 이미 겪었다고 적고 있다.
|
||
- [Save] 는 화면에 실린 줄을 **지금 고른 파일 경로**에 쓴다. 화면 내용이 어느 파일의 것인지 대조하지 않는다.
|
||
- 방향:
|
||
1. 늦게 끝난 로드는 **읽기 시작한 경로 · 커밋이 지금 것과 다르면 버린다.**
|
||
2. 저장은 **화면에 실린 내용의 경로**를 들고 있다가 그 경로와 지금 고른 파일이 다르면 쓰지 않는다(쓰기 전에 막고 알린다). 두 겹으로 막는다.
|
||
3. 같은 뿌리가 있는지 본다 — 저장 뒤 다음 파일 열기(`ReloadAfterResolveAsync`), 파일 지우기/남기기 띠, 파일 콤보를 빠르게 바꾸기, git mergetool 세 벌 열기.
|
||
- **판정 기준**:
|
||
- 위 순서 그대로(파일 비교 탭을 처음 여는 것이 [3분할로 열기])에서 **고른 파일(Unit47)이 열린다.** 병합 · pull · rebase · cherry-pick 넷 다.
|
||
- 어떤 순서로도 [Save] 가 **화면에 보이는 파일이 아닌 파일에 쓰지 않는다.** 하네스로 "로드 도중 선택이 바뀜 · 저장 경로와 화면 경로가 다름" 을 만든다.
|
||
- 네 길 결과 커밋에서 class 이름이 다른 `UnitN.cs` 0 개. 저장 뒤 다음 파일이 저절로 열리는 흐름(6차 A-2 · B-1)은 그대로.
|
||
|
||
---
|
||
|
||
## B. 작업마다 화면이 사실대로 말하게
|
||
|
||
### B-1. rebase · cherry-pick 에서 마지막 저장 뒤 "남은 차이" 가 뜬다 (7차 D-1 N2)
|
||
|
||
- rebase · cherry-pick 마지막 충돌 파일을 [Save] 하면 파일 비교 탭이 두 칸(`짧은해시 · Weld/Unit1.cs`)으로 떨어져 **"남은 차이 3줄"** 을 보인다.
|
||
충돌 탭은 "충돌 정리 끝 - [계속] 으로 rebase 를 이어 갑니다"(cherry-pick 은 "[커밋] 으로 …")라 두 화면이 다른 말을 한다. 7차 A-1 과 같은 증상.
|
||
- 짚이는 곳: A-1 의 `MergeSavePlan.ResolvedMergeSummary` · 제목 "병합 전 내 쪽" 이 `IsMergeInProgress`(병합 표시)일 때만 쓰인다.
|
||
7차 C-2 에서 만든 `GitOperationState` · `OperationLabels` 를 따르지 않는다.
|
||
- 방향: 작업이 진행 중이고 충돌이 0 이면 작업에 맞게 말한다 — rebase 는 "충돌 정리 끝 · [계속] 으로 이어 갈 수 있습니다", cherry-pick · revert 는 "… [커밋] 으로 끝낼 수 있습니다".
|
||
제목의 "병합 전 내 쪽" 도 작업에 맞는 이름(rebase 는 "올릴 자리")으로.
|
||
- **판정 기준**: 네 길 모두 마지막 [Save] 뒤 파일 비교 탭의 요약 · 제목이 충돌 탭과 같은 말을 한다. 병합 글은 7차 A-1 그대로(하네스로 확인).
|
||
|
||
### B-2. 바뀌는 것 없는 cherry-pick 에서 [커밋] 이 켜지고 누르면 실패한다 (7차 D-1 N4)
|
||
|
||
- 이미 들어 있는 커밋(HEAD)을 cherry-pick 하면 `CHERRY_PICK_HEAD` 만 생긴다. 충돌 탭 [커밋] 이 켜지고, 누르면
|
||
로그에만 **"[cherry-pick 커밋] 실패: No changes; nothing to commit."** 이 남는다. 진행 줄은 "충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다" 그대로라 같은 단추를 또 누르게 된다.
|
||
[작업 취소] 로는 빠져나온다. (시작 로그 "적용됨 - 확인한 뒤 [커밋] 으로 끝냅니다" 도 이 경우엔 맞지 않다.)
|
||
- 방향: 스테이징된 변경이 없으면 [커밋] 을 끄고 "가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다" 로 말한다.
|
||
git 처럼 빈 cherry-pick 을 커밋으로 남기는 길(`--allow-empty`)을 둘지는 **사용자에게 묻고** 정한다 — 정하기 전에는 두지 않는다.
|
||
- **판정 기준**: 빈 cherry-pick 에서 [커밋] 이 꺼져 있고 안내가 [작업 취소] 를 말한다. 누를 수 있는 단추가 실패로 끝나는 일이 없다. 충돌이 있던 cherry-pick 은 7차 C-2 그대로.
|
||
|
||
### B-3. MERGED 칸 줄 번호가 결과 파일 번호가 아니다 (7차 D-1 N3) — **먼저 정한다**
|
||
|
||
- `Motion/Unit0.cs` 에서 고른 줄 · 머지 주석으로 결과가 3줄 늘어 상태바는 "3366행 · 총 3366줄" 인데, MERGED 칸 끝 번호는 3363 이고 줄마다 LOCAL 칸과 같은 번호다.
|
||
네 자리가 잘리지는 않는다(6차 B-4 · 7차 D-1 에서 확인).
|
||
- 짚이는 곳: MERGED 칸 번호는 `LocalNumberText` — 정렬할 때 정한 번호를 쓰고 편집 뒤 다시 매기지 않는 것으로 보인다. 새로 들어간 주석 줄은 번호가 비는지 확인한다.
|
||
- **설계였을 수도 있다**(LOCAL 과 같은 번호여야 옆 칸과 맞대 보기 쉽다). 고치기 전에 **사용자에게 두 가지를 보이고 정한다.**
|
||
① MERGED 는 결과 파일 번호(상태바 · 이동 칸 · 컴파일 오류와 같은 번호) ② 지금처럼 내 쪽 번호, 대신 칸 제목이나 상태바에 그렇다고 적는다.
|
||
- **판정 기준**: 정한 대로 MERGED 칸 번호 · 상태바 행 · [이동] 칸 · 코드 검사 "N행" 이 같은 기준을 쓴다. 번호가 서로 달라 보이는 곳이 없다(스크린샷).
|
||
|
||
---
|
||
|
||
## C. 7차에서 남긴 것
|
||
|
||
### C-1. revert 충돌을 화면으로 끝까지
|
||
|
||
- 7차 C-2 에서 revert 는 rebase · cherry-pick 과 같은 길(`AfterConflicts` · `CommitPendingOperation`)을 쓰게 했지만 **화면으로 끝까지 해 본 적이 없다.**
|
||
- 생성기(`C1Repo`)에 revert 가 충돌을 내는 갈래를 더한다(같은 씨앗, 기존 경우는 그대로).
|
||
- **판정 기준**: 이력 탭에서 커밋을 골라 [Revert] → 충돌을 네 칸으로 풀고 → 충돌 탭 [커밋] 까지 MergeHub 만으로.
|
||
칸 제목 "되돌리는 커밋 …" · 진행 표시 "revert 진행 중" · 원래 revert 메시지. 줄끝 · BOM 바뀐 파일 0, class 이름 검사 0.
|
||
|
||
### C-2. cherry-pick 이 원래 작성자를 남기는지 눈으로
|
||
|
||
- 시험 저장소의 모든 커밋 작성자가 `시험` 이라 7차 C-2 에서는 코드로만 확인했다.
|
||
- 생성기에서 상대 쪽 커밋의 작성자를 다른 사람으로 만든다.
|
||
- **판정 기준**: cherry-pick · revert 커밋의 작성자가 git 과 같다(cherry-pick 은 원래 작성자 · 커밋한 사람은 지금 사용자). git 으로 같은 일을 한 결과와 견준다.
|
||
|
||
### C-3. 창 크기 조절에서 안 본 것 (7차 E-4, 플랫폼)
|
||
|
||
- **화면 가장자리 스냅**(창을 왼쪽 · 오른쪽 끝으로 끌어 반쪽, Win+← / →)을 두 모니터(150% · 100%)에서 본다. 반쪽 크기가 최소 1280 × 720 보다 작아지는 경우의 모양도.
|
||
- **기억이 없을 때 첫 Win+↓** 는 XAML 기본 크기(1600 × 900 DIP)로 내려오고, 두 번 누르기로 복원하면 작업 영역의 80% 다. 둘을 같게 맞출지 본다.
|
||
- 잠금 화면 · 알림 · 이름 창 · 확인 창이 **보통 크기 창의 가운데**에 뜨는지 스크린샷으로 남긴다(7차 E-4 판정 기준 중 기록이 얇은 것).
|
||
- 보통 크기 창 가장자리의 1px Windows 테두리 선은 그대로 둘지 사용자와 정한다.
|
||
- **판정 기준**: 위 넷을 실제 픽셀로 확인해 적는다. 고친다면 플랫폼 changelog 에 영향을 적고, 배포는 사용자 확인 뒤.
|
||
|
||
---
|
||
|
||
## D. 문서
|
||
|
||
### D-1. 웹 문서를 7차 · 8차에 맞게
|
||
|
||
- `doc\web\index.html`(사용자 매뉴얼 · 발표 자료 · 남은 일 · 개발 현황)이 **6차에서 멈춰 있다.**
|
||
7차의 [Save] 이름 · 충돌 네 칸 머리 글 · rebase / cherry-pick 제목과 끝내기 단추 · 이력 [모든 브랜치] · pull 뒷일 · 폴더 차례 끌어 놓기 · 이름 창 잠금 · 창 크기 조절이 없다.
|
||
매뉴얼의 **"알아 둘 한계"** 목록에는 7차에서 사라진 것이 남아 있다.
|
||
- A · B 를 고친 뒤 한 번에 맞춘다. 지난 기록(history)은 그때 이름 그대로 둔다.
|
||
- **판정 기준**: 문서에 적힌 단추 이름 · 흐름이 지금 화면과 같다(화면 문구를 grep 으로 대조). "알아 둘 한계" 에 8차 끝 기준으로 남은 것만 있다. 발행된 아티팩트도 같은 내용으로 갱신.
|
||
|
||
---
|
||
|
||
## E. 확인
|
||
|
||
### E-1. 네 길(+ revert)을 사람 순서 그대로 다시 끝까지
|
||
|
||
- A ~ C 를 고친 뒤 저장소를 새로 만들어 **병합 · pull · rebase · cherry-pick · revert** 를 각각 처음부터 끝까지 한다.
|
||
- 7차 D-1 과 달리 **파일 비교 탭을 미리 열어 두지 않는다** — 충돌 탭의 [3분할로 열기] 로 처음 연다(A-1 을 그대로 밟는 순서).
|
||
- 7차 D-1 과 **같은 표로** 적는다. 새로 걸린 것은 고치지 말고 적는다 — 그 목록이 9차가 된다.
|
||
- **판정 기준**: 다섯 길 모두 MergeHub 만으로 끝까지. 줄끝 · BOM 이 바뀐 파일 0 · 충돌 표식 0 · **class 이름이 다른 Unit 파일 0**.
|
||
7차 A-1 · A-2 · B-1 과 8차 A-1 · B-1 · B-2 가 다시 나지 않는다.
|
||
|
||
---
|
||
|
||
## F. 추가 요청
|
||
|
||
### F-1. 병합 커밋 메시지 본문에 충돌 해결 내역을 자동으로 적기 (2026-09-17, 사용자)
|
||
|
||
사용자: "파일단위 머지할때 이력은 그럼 어디남아?" → 제안 중 "병합 커밋 메시지 본문에 해결 내역을 자동으로 적기" 로 정함. "스타일 맞추는건 안할거야"(비교할 때만 스타일을 맞추고 저장은 원래대로 하는 선택지는 만들지 않는다).
|
||
|
||
**지금 모양** — 충돌을 어떻게 풀었는지가 오래 남는 곳이 없다.
|
||
|
||
| 어디 | 남는 것 | 한계 |
|
||
|---|---|---|
|
||
| 소스 | 네 칸에서 줄을 가져오면 `// [이름] 날짜` 주석 | 충돌 탭 **파일 단위 Accept** 는 고른 쪽 파일을 바이트째 써서 주석이 없다 |
|
||
| git 병합 커밋 | 부모 둘 · 제목 · 작성자(git `user.name`) | "이 파일은 Theirs 로 골랐다" 가 직접 적히지 않는다 — 7차 D-1 · 8차 A-1 의 병합 커밋 본문은 비어 있었다 |
|
||
| Git 탭 로그 | `충돌 해결(Theirs): 경로` | 화면에만 있고 끄면 사라진다 |
|
||
| 플랫폼 로그 | `버튼 클릭: Accept Theirs` | 파일 이름도 사람도 없다 |
|
||
|
||
**방향**
|
||
- 병합(및 pull) 중에 충돌을 풀 때마다 **무엇으로 풀었는지** 적어 둔다 — 줄 단위(Save) · Accept Mine · Accept Theirs · Accept Both · 파일 남기기 · 파일 지우기 · 머지 주석 자동. 앱을 껐다 켜도 이어지게 `.git` 에 적고, 처음 충돌 목록(`MERGEHUB_CONFLICTS`)과 같은 규칙(첫 줄 MERGE_HEAD · 병합 커밋 · 작업 취소 · 새로고침 때 쓸모없으면 치움)을 따른다.
|
||
- [병합 커밋](Save & Commit 포함) 때 본문에 **"충돌 해결 N개 · 이름"** 과 갈래별 파일 목록을 붙인다. Git 탭 메시지 칸에도 미리 채워 보인다. 사람이 칸을 고쳐도 커밋 때 블록은 붙는다(유일한 기록이므로).
|
||
- cherry-pick · revert · rebase 는 원래 커밋 메시지를 쓰므로 이번에는 적지 않는다.
|
||
|
||
**판정 기준**
|
||
- 만든 저장소를 MergeHub 로 병합해 여러 방법으로 풀고 [병합 커밋] 하면, `git log -1 --format=%B` 본문에 방법별 파일이 모두 적힌다. 파일 수 합 = 푼 충돌 수.
|
||
- 병합 커밋 · 작업 취소 뒤 기록 파일이 남지 않는다. 다음 병합에 지난 기록이 섞이지 않는다.
|
||
- 병합 제목 · 커밋 방식 · 줄끝 등 7차 · 8차 결과는 그대로(회귀 없음).
|
||
|
||
---
|
||
|
||
## 이번 지시서에서 하지 않는 것
|
||
|
||
- **실제 소스로 병합해 보기** — 실제 소스는 열지 않는다(2026-09-11 결정).
|
||
- **머지 주석을 병합에서 끄기** — 6차 B-5 에서 "소스에 넣고 비교 · 병합에서는 무시" 로 정했다. 7차 D-1 네 길에서도 그대로 동작했다.
|
||
- 빠른 비교(크기 · 수정일)가 내용만 바뀐 파일을 놓치는 것 — 폴더 비교의 알려진 한계로 둔다.
|
||
- 같은 줄 접기(4차 B-2) · 외부 편집기(4차 B-4) · 로그인·권한 · Gitea PR — 미룬 그대로 둔다.
|
||
- 파일 단위 Accept 가 고른 쪽 파일의 줄끝을 그대로 가져오는 것(7차 C-2) — 고른 대로라 결함으로 보지 않는다.
|
||
|
||
---
|
||
|
||
## 보고 형식
|
||
|
||
항목마다 이렇게 적는다.
|
||
|
||
- 고치기 전에 문제가 **다시 나는 것**을 어떻게 보였는지 (만든 저장소의 어느 파일로)
|
||
- 무엇이 원인이었는지 한두 줄
|
||
- 어떤 파일을 어떻게 고쳤는지
|
||
- 실제로 실행해 확인한 결과 (바이트 · 줄끝 · 충돌 수 · class 이름처럼 **눈이 아닌 값**으로)
|
||
- 커밋 해시
|