파일 비교 탭을 처음 여는 것이 [3분할로 열기] 면 고른 파일 대신 첫 충돌 파일이 보였고, 그 화면을 [Save] 하면 고른 파일에 그 내용이 써졌다(Unit47 이 Unit15 내용으로 스테이징). - 읽기: 읽는 사이 파일 · 커밋이 바뀌면 버리고, 화면이 지금 고른 파일과 다르면 한 번 더 읽는다 - 쓰기: 저장 · Save & Commit · 파일 지우기/남기기가 화면에 실린 파일과 다르면 아무것도 쓰지 않는다 - 하네스 MergeSaveTest 15건 추가(140건), 18벌 906건 통과 확인: 병합 · pull · rebase · cherry-pick 네 길 모두 고른 파일이 열리고 저장이 그 파일에만 감. 병합은 파일 비교 탭을 미리 열지 않고 끝까지 - 커밋 3ba6314, 줄끝 · BOM 0/33, class 이름 검사 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
5.5 KiB
Markdown
73 lines
5.5 KiB
Markdown
# 8차 — 고른 파일에 고른 내용을 · 작업마다 화면이 사실대로 (2026-09-16 ~)
|
|
|
|
지시서: [../작업지시/8차.md](../작업지시/8차.md). 7차 D-1 에서 새로 걸린 넷과 7차에서 남긴 것 · 웹 문서.
|
|
|
|
## A-1. 고른 충돌 파일 대신 다른 파일이 보이고, 그 화면을 저장하면 고른 파일에 써진다 (2026-09-16, 완료)
|
|
|
|
### 고치기 전에 다시 났다 (새로 만든 저장소, MergeHub 로 병합)
|
|
|
|
파일 비교 탭을 **한 번도 열지 않은 채** Git 탭 충돌 목록에서 `Common/Util/Unit47.cs` 를 고르고 [3분할로 열기].
|
|
|
|
| 확인 | 결과 |
|
|
|---|---|
|
|
| 파일 비교 탭 화면 | **`(merge base) Common/Util/Unit15.cs`** — 고른 파일이 아니라 첫 충돌 파일 |
|
|
| [다음 충돌] → Take Theirs → [Save] | 눌린다 |
|
|
| git | **`M Common/Util/Unit47.cs`** · `UU Common/Util/Unit15.cs` |
|
|
| 스테이징된 `Unit47.cs` 내용 | **123줄 · `public sealed class Unit15`** — Unit15 의 내용(고른 줄 · 머지 주석까지)이 Unit47 에 써졌다 |
|
|
| 로그 | `충돌 해결(직접 편집, UTF-8 (BOM) · CRLF): Common/Util/Unit47.cs` |
|
|
| 저장 뒤 화면 | 30초 동안 Unit15 · "남은 충돌 1개" 그대로 |
|
|
|
|
7차 D-1 에서 병합 · pull 둘 다 이렇게 났다(그때는 파일 비교 탭을 먼저 열어 두고 네 길을 확인했다).
|
|
|
|
### 원인
|
|
|
|
파일 비교 화면은 **탭을 처음 열 때 만들어진다.** 그때 두 가지가 겹친다.
|
|
|
|
1. 목록 세우기(`RebuildListAfterRefreshAsync` → `LoadCommitAsync`)가 첫 파일(`Unit15`)을 읽는다.
|
|
2. 넘겨받은 요청(`DeliverPendingOpenConflict` → `OpenConflictAsync`)이 고른 파일(`Unit47`)을 고른다.
|
|
|
|
`LoadFileAsync` 는 읽기가 끝난 뒤 **늦게 끝난 결과를 `IsGitMode` 로만 버렸다.** 읽기 시작한 경로가 지금 고른 파일과 같은지는 보지 않았다
|
|
(같은 자리 주석이 "경로는 새 파일인데 내용은 옛 파일" 을 이미 겪었다고 적고 있었다 - 데모 전환에서).
|
|
그래서 Unit15 의 내용이 화면을 덮었고, [Save] 는 화면 내용을 **지금 고른 파일**(Unit47)에 썼다.
|
|
|
|
### 고친 것
|
|
|
|
| 파일 | 무엇 |
|
|
|---|---|
|
|
| `Services/MergeSavePlan.cs` | `IsStaleLoad(읽은 경로 · 읽은 커밋, 지금 경로 · 지금 커밋)` — 읽는 사이에 파일 · 커밋이 바뀌었으면 버린다. `ShownFileMismatch(화면에 실린 파일, 저장할 파일)` — 다르거나 실린 것이 없으면 까닭을 돌려준다 |
|
|
| `ViewModels/HomeViewModel.cs` | `_shownFile` — **화면에 실제로 실린 파일**. `LoadFileAsync` 는 행을 만들기 전과 화면에 옮기기 직전 두 곳에서 `IsStaleLoad` 로 버리고, 실을 때 `_shownFile` 을 적는다. 버린 뒤 화면이 지금 고른 파일과 다르면 `ReloadWhenShownIsStale` 로 **한 번 더 읽는다**(되풀이 방지 플래그). `ClearPanes` 는 `_shownFile` 을 지운다 |
|
|
| 〃 | 쓰기 세 길(`SaveAndCommitAsync` · `SaveResolvedAsync` · `DecideDeletionAsync`)이 **아무것도 쓰기 전에** `ShownFileMismatch` 로 막고 알린다 |
|
|
| 하네스 `MergeSaveTest` | 검사 15건 — 같은 파일 · 다른 파일 · 다른 커밋 · 선택 없음 · 경로 구분자 · 대소문자 · 해시 대소문자, 저장 막기(같음 · 다름 · 두 이름이 까닭에 들어감 · 화면이 빔 · 저장할 파일이 빔) |
|
|
|
|
읽기 쪽만 고치고 끝내지 않았다. 되돌릴 수 없는 쓰기 앞에 문을 하나 더 뒀다.
|
|
|
|
**고치는 중에 한 번 더 걸렸다.** 버리기만 했더니 [3분할로 열기] 로 처음 열 때 **화면이 빈 채로** 남았다(단추도 없음).
|
|
버린 뒤 다시 읽는 `ReloadWhenShownIsStale` 을 넣어 고쳤다.
|
|
|
|
### 확인한 것 (길마다 저장소를 새로 만들어, 파일 비교 탭을 미리 열지 않고)
|
|
|
|
| 길 | [3분할로 열기] 뒤 화면 | Save 뒤 git | 스테이징된 Unit47 안의 class |
|
|
|---|---|---|---|
|
|
| 병합 | **`(merge base) Common/Util/Unit47.cs`** · 남은 충돌 1개 · REMOTE `feature/theirs` | `M Unit47.cs` · `UU Unit15.cs` | **Unit47** |
|
|
| pull | 같음 | 같음 | **Unit47** |
|
|
| rebase | 같음 · REMOTE `다시 올리는 내 커밋 1839bd3` | 같음 | **Unit47** |
|
|
| cherry-pick | 같음 · REMOTE `가져오는 커밋 f707175` | 같음 | **Unit47** |
|
|
|
|
이어서 **병합을 사람 순서 그대로 끝까지**(파일 비교 탭을 미리 열지 않고) 했다.
|
|
|
|
| 확인 | 결과 |
|
|
|---|---|
|
|
| 파일 단위 Accept Theirs 15개 | 24 → 9, 1.0초 |
|
|
| 3분할로 푼 파일 | NewPanel · Unit47 · 한글설명 · LineEnding · Unit0(6) · 띠 둘 · View250 · Unit1(6) — 저장할 때마다 다음 파일이 저절로 열림 |
|
|
| 마지막 Save 뒤 | `12b0402 · Weld/Unit1.cs · 병합 전 내 쪽` · 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 3줄 (7차 A-1 그대로) |
|
|
| 병합 커밋 | `3ba6314` 부모 둘 · `Merge branch 'feature/theirs' into feature/mine` · 워킹트리 Clean |
|
|
| 줄끝 · BOM · 인코딩이 첫 부모와 다른 파일 | **0 / 33** · 충돌 표식 0줄 |
|
|
| class 이름이 파일 이름과 다른 Unit 파일 | **0** |
|
|
|
|
하네스 18벌 906건 통과(MergeSaveTest 140). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
|
|
|
|
### 남긴 것
|
|
|
|
- 자동 조작 쪽: Save 직후 찍은 화면이 Git 탭이라 파일 비교 탭 제목이 빈 것으로 읽혔다. 화면은 제대로였다(스크린샷).
|
|
- 7차 D-1 때 넣은 우회(파일 비교 탭을 먼저 한 번 열기)는 스위치(`D7_NO_PREOPEN`)로 껐다 켤 수 있게 두었다. 8차 E-1 은 끈 채로 한다.
|