Ubisam-MergeTool/doc/history/2026-09-16-8차.md
ksj09406 18f9ca3a9f 8차 E-1 기록: 다섯 길을 사람 순서 그대로 다시 끝까지
제품 코드 변경 없음. 병합 · pull · rebase · cherry-pick · revert 를 길마다 새 저장소에서
파일 비교 탭을 미리 열지 않고 MergeHub 만으로 끝까지 갔다.

- 다섯 길 모두 커밋(rebase 끝)까지 · 줄끝 · BOM 바뀐 파일 0 · 충돌 표식 0 · class 이름 검사 0
- 7차 A-1 · A-2 · B-1, 8차 A-1 · B-1 · B-2 다시 안 남 · F-1 병합 · pull 본문 26개
- 새로 걸린 것(9차): cherry-pick 마지막 저장 뒤 요약 "내 쪽 대비" 가 실제 기준(이력에서 고른 커밋)과 다름,
  한 번 다른 브랜치 커밋이 기준으로 잡힘(따로 재니 재현 안 됨)
- 8차 전부 끝

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 10:32:55 +09:00

479 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 은 끈 채로 한다.
## B-1. rebase · cherry-pick 에서 마지막 저장 뒤 "남은 차이" 가 뜬다 (2026-09-16, 완료)
### 고치기 전에 다시 났다 (길마다 저장소를 새로 만들어)
마지막 한 파일(`Weld/Unit1.cs`)만 남기고 23개를 파일 단위로 풀고, 남은 하나를 네 칸에서 Take Theirs 6번 → [Save].
| 길 | 파일 비교 탭 | 충돌 탭 |
|---|---|---|
| rebase | `bbdc66e · Weld/Unit1.cs` · **남은 차이 6줄** | 충돌 정리 끝 - [계속] 으로 rebase 를 이어 갑니다 |
| cherry-pick | `30c2133 · Weld/Unit1.cs` · **남은 차이 6줄** | 충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다 |
| 병합 (회귀) | `c3691b2 · Weld/Unit1.cs · 병합 전 내 쪽` · 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 6줄 | 같은 말 |
두 화면이 다른 말을 한다. 방금 받아 놓은 6줄이 "아직 할 일" 로 읽힌다 — 7차 A-1 과 같은 증상인데 병합에서만 고쳐져 있었다.
### 원인
7차 A-1 에서 만든 `MergeSavePlan.ResolvedMergeSummary` · `MergeBaseHeader` 가 **병합 전용**이었다.
화면도 `_workspace.IsMergeInProgress`(MERGE_HEAD 기준)로 물었다. rebase 는 MERGE_HEAD 가 없고 cherry-pick 은 `CHERRY_PICK_HEAD` 라 둘 다 "병합 중이 아님" 이 되어 보통 요약("남은 차이 N줄")으로 떨어졌다.
7차 C-2 에서 만든 작업 상태(`GitOperationState` · `OperationLabels`)를 쓰지 않고 있었다.
### 고친 것
| 파일 | 무엇 |
|---|---|
| `Services/OperationLabels.cs` | `ResolvedSummary(작업, 남은 충돌, 차이 줄)` — 끝말은 진행 줄과 같은 `FinishHint`(병합 커밋 · [계속] · [커밋])를 쓴다. 차이 줄은 작업마다 무엇인지 적는다(받은 변경 · 올린 변경 · 가져온 변경 · 되돌린 변경). `BaseHeader(작업, 짧은해시, 경로)` — 병합 "병합 전 내 쪽", rebase **"올릴 자리"**, cherry-pick "가져오기 전 내 쪽", revert "되돌리기 전 내 쪽" |
| `Services/MergeSavePlan.cs` | 병합 전용이던 `ResolvedMergeSummary` · `MergeBaseHeader` 를 걷어냈다(글은 위로 옮김) |
| `ViewModels/HomeViewModel.cs` | 요약 · BASE 제목이 `IsMergeInProgress` 대신 **`IsOperationInProgress` · `OperationState.Kind`** 를 본다 |
| 하네스 `MergeSaveTest` | 병합 글이 예전과 같은지 6건 + 작업별 요약 · 제목 10건 |
### 확인한 것 (같은 순서로 다시)
| 길 | 마지막 Save 뒤 파일 비교 탭 | 충돌 탭 |
|---|---|---|
| rebase | **`3e51519 · Weld/Unit1.cs · 올릴 자리`** · **충돌 정리 끝 · [계속] 으로 rebase 를 이어 갑니다 · 올릴 자리 대비 올린 변경 6줄** | 같은 말 |
| cherry-pick | **충돌 정리 끝 · [커밋] 으로 cherry-pick 을 끝냅니다** | 같은 말 |
| 병합 (회귀) | `d091ca2 · Weld/Unit1.cs · 병합 전 내 쪽` · 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · 내 쪽 대비 받은 변경 6줄 | 같은 말 |
cherry-pick 의 BASE 제목에 꼬리가 없는 것은 맞다 — 그때 BASE 는 HEAD 가 아니라 **이력에서 고른 가져올 커밋**이라
"가져오기 전 내 쪽" 이라고 하면 틀린 말이 된다(제목은 `14a9476 · Weld/Unit1.cs`, HEAD 는 `45bdbf5`).
하네스 18벌 914건 통과(MergeSaveTest 148). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
## B-2. 바뀌는 것 없는 cherry-pick 에서 [커밋] 이 켜지고 누르면 실패한다 (2026-09-16, 완료)
### 고치기 전에 다시 났다 (새로 만든 저장소, 이력에서 HEAD 커밋을 골라 [Cherry-pick])
| 때 | 결과 |
|---|---|
| [Cherry-pick] | 로그 `cherry-pick 적용됨 - 확인한 뒤 충돌 탭의 [커밋] 으로 끝냅니다.` · `.git` 에 `CHERRY_PICK_HEAD` |
| 충돌 탭 | 머리 `cherry-pick 진행 중` · 진행 줄 **`충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다`** · **[커밋] 켜짐** |
| [커밋] 을 눌러 봄 | 로그 **`[cherry-pick 커밋] 실패: No changes; nothing to commit.`** · HEAD 그대로 · 알림은 읽히지 않음 |
| 그 뒤 | 진행 줄 · [커밋] 이 그대로라 **같은 단추를 또 누르게 된다.** [작업 취소] 로는 빠져나온다 |
### 원인
- 끝내기 단추(`CanFinishOperation`)는 "작업이 진행 중 · 충돌 0" 만 봤다. **커밋할 것이 있는지는 보지 않았다.**
- 진행 줄(`OperationLabels.ProgressText`)도 충돌이 0 이면 무조건 "끝낼 수 있다" 고 말했다.
- 시작 로그(`BuildPatchResult`)는 적용 결과가 `Applied` 면 늘 "확인한 뒤 [커밋] 으로 끝냅니다" 였다.
- 실제로 막은 것은 libgit2 였고, 그 말(`No changes; nothing to commit.`)이 로그에 그대로 나왔다.
### 고친 것
| 파일 | 무엇 |
|---|---|
| `Services/GitService.cs` | `HasStagedChanges()` — 인덱스가 HEAD 와 다른가. cherry-pick 적용 로그가 이걸 보고 **"cherry-pick 했지만 가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다."** 로 적는다(revert 는 "되돌릴"). `CommitPendingOperation` 은 커밋 전에 같은 것을 보고 사람 말로 막는다 |
| `Services/IGitService.cs` | 선언 |
| `Services/GitWorkspace.cs` | `PendingHasChanges` — 상태를 읽을 때 함께 읽어 둔다. 진행 줄이 이 값을 쓴다 |
| `Services/OperationLabels.cs` | `ProgressText(…, hasChanges)` — 충돌 0 인데 가져올 것이 없는 cherry-pick · revert 는 **"가져올(되돌릴) 변경이 없습니다 - [작업 취소] 로 끝냅니다"**. 병합 · rebase 는 따지지 않는다(병합 커밋은 트리가 같아도 정상이다) |
| `ViewModels/GitViewModel.cs` | `CanFinishOperation` — cherry-pick · revert 는 커밋할 것이 있어야 켜진다 |
| 하네스 `MergeSaveTest` | 진행 줄 검사 7건(없음 · revert · 있음 · 충돌 남음 · 병합 · rebase · 기본값이 예전과 같은지) |
**병합 커밋에는 걸지 않았다.** 처음에 `CommitMerge` 에도 같은 막음을 넣었다가 뺐다 — 병합은 가져올 변경이 없어도(양쪽이 같게 고친 경우 등) 커밋이 정상이다.
### 확인한 것 (저장소를 새로 만들어)
| 경우 | 결과 |
|---|---|
| ① HEAD 커밋을 다시 [Cherry-pick] | 로그 **`cherry-pick 했지만 가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다.`** · 진행 줄 **`가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다`** · **[커밋] 꺼짐** · [작업 취소] 켜짐 |
| ① [작업 취소] | `CHERRY_PICK_HEAD` 없어짐 · 머리 표시 · 진행 줄 사라짐 |
| ② 회귀 - 충돌 24건짜리 보통 cherry-pick | 충돌 중 [커밋] 꺼짐 → 다 풀면 진행 줄 `충돌 정리 끝 - [커밋] 으로 cherry-pick 을 끝냅니다` · [커밋] 켜짐 → 누르면 `cherry-pick 커밋: e35f7b7 상대 쪽 작업`(부모 하나 · 원래 메시지) |
하네스 18벌 921건 통과(MergeSaveTest 155). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
### 정하지 않은 것
- git 의 `--allow-empty` 처럼 **빈 cherry-pick 을 커밋으로 남기는 길**은 지시서대로 두지 않았다. 사용자와 정한 뒤에 넣는다.
## B-3. MERGED 칸 줄 번호가 결과 파일 번호가 아니다 (2026-09-16, 완료)
**정한 것 (2026-09-16, 사용자)** — 두 가지를 보이고 골랐다. ① 결과 파일 번호로(고름) ② 지금처럼 내 쪽 번호로 두고 그렇다고 적기.
결과 파일 번호는 상태바 · [이동] 칸 · 코드 검사의 "N행" 과 같은 기준이다.
### 고치기 전에 다시 났다 (새로 만든 저장소, 병합 중 `Motion/Unit0.cs` 를 네 칸으로)
충돌 6개를 Take Theirs 하면 고른 줄 · 머지 주석으로 결과가 늘어난다.
| 확인 | 값 |
|---|---|
| 상태바 | **총 3369줄** |
| [이동] 칸에 3369 | 3369행으로 감 |
| **MERGED 칸 끝 번호** | **3363** — 여섯 줄이 모자란다 |
| LOCAL (Mine) 칸 끝 번호 | 3361 (내 파일 그대로 · 맞다) |
### 원인
MERGED 칸 번호는 `MergeLine.LocalNumber` 인데, 이 값은 **정렬기가 짝지을 때 한 번 정해지고 그대로**다.
머지 주석 줄은 새로 끼워 넣으면서 번호를 주지 않았고(`Lines.Insert`), 그 뒤의 줄들도 번호를 다시 매기지 않았다.
그래서 결과가 길어질수록 어긋난다.
### 고친 것
| 파일 | 무엇 |
|---|---|
| `Services/MergedNumbering.cs` (새 파일) | `Assign(결과에 들어가는가[])` — 결과에 들어가는 줄만 1부터 센다. `Count` — 결과 줄 수 |
| `ViewModels/HomeViewModel.cs` | `RenumberMerged(rows)` — 줄 목록에 결과 번호를 다시 매긴다. 두 줄 만들기(두 칸 · 네 칸) 끝과 **요약을 그릴 때마다**(고르기 · 편집 · 되돌리기 · 주석 끼우기 뒤) 부른다 |
| 하네스 `MergeSaveTest` | 번호 검사 7건(결과에 없는 줄 · 끝 번호 = 결과 줄 수 · 빈 목록 · null 등) |
결과 파일은 `BuildLocalText` 가 `HasLocal` 인 줄만 이어 붙인 것이라, 번호도 같은 기준으로 센다.
LOCAL (Mine) 칸은 `OriginalLocalNumber`(내 파일 번호)를 그대로 쓴다 — 바꾸지 않았다.
### 확인한 것 (같은 순서로 다시)
| 확인 | 값 |
|---|---|
| 상태바 | 총 3369줄 |
| **MERGED 칸 끝 번호** | **3369** (3352 ~ 3369) |
| [이동] 칸에 3369 | 3369행 |
| **[Save] 한 뒤 워킹트리 파일** | **3369줄** — 화면 번호와 같다 |
| LOCAL (Mine) 칸 | 3346 ~ 3361 그대로 |
하네스 18벌 928건 통과(MergeSaveTest 162). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
## C-1. revert 충돌을 화면으로 끝까지 (2026-09-16, 완료)
7차 C-2 에서 revert 는 rebase · cherry-pick 과 같은 길을 쓰게 했지만 **화면으로 끝까지 해 본 적이 없었다.**
### 시험 재료를 먼저 만들었다 (생성기 `C1Repo`, 같은 씨앗)
revert 가 충돌을 내려면 되돌릴 줄을 **뒤이어 또 고친 커밋**이 있어야 한다. 갈래를 하나 더했다.
- `feature/revert` = `내 쪽 작업` 위에 `뒤이은 수정` 하나. 같은 줄 충돌 15개 파일과 큰 파일 `Motion/Unit0.cs` 의 같은 자리를 또 고친다.
- 기존 경우(병합 · pull · rebase · cherry-pick)는 그대로다 — `feature/mine` · `feature/theirs` 를 건드리지 않았다.
- git 으로 미리 재 보니 그 위에서 `내 쪽 작업` 을 revert 하면 **충돌 16개**다.
### 확인한 것 (MergeHub 만으로)
| 때 | 결과 |
|---|---|
| 이력에서 `내 쪽 작업` 을 골라 [Revert] | 알림 **`충돌 16건 - … 다 풀면 [커밋] 으로 revert 를 끝냅니다.`** · 로그 `revert 시작: c579a81 내 쪽 작업` → `revert 충돌 16건 - 풀고 나서 충돌 탭의 [커밋] 으로 끝냅니다.` |
| 충돌 중 | 머리 **`revert 진행 중`** · [작업 취소] 켜짐 · 진행 줄 `남은 충돌 16개` · 끝내기 단추 **[커밋]**(꺼짐) |
| 네 칸 (`Motion/Unit0.cs`) | LOCAL `feature/revert` · REMOTE **`REMOTE · 되돌리는 커밋 c579a81 내 쪽 작업`** · 머리 글 **`revert 충돌 · REMOTE = 되돌리는 커밋 c579a81`** · "3-Way 안 씀" 없음 |
| 줄을 고르면 | 로그 **`101행 Theirs(커밋 c579a81) 반영`** (6줄) |
| 나머지 15개 파일 단위 Accept Theirs | git 충돌 15 → **0** |
| 다 푼 뒤 | 진행 줄 **`충돌 정리 끝 - [커밋] 으로 revert 를 끝냅니다`** · [커밋] 켜짐 · 커밋 메시지 칸 **`Revert "내 쪽 작업"` + `This reverts commit c579a81…`** |
| [커밋] | 로그 `revert 커밋: acefbcd Revert "내 쪽 작업"` · 부모 하나 · 진행 표시 · [작업 취소] 사라짐 · 워킹트리 Clean |
| 결과 | `Common/Util/Unit15.cs` 가 **바탕과 같아짐** · 되돌린 글("내가 고침") 0개 파일 · `REVERT_HEAD` 없음 |
| 바이트 | 바뀐 파일 36개 · **줄끝 · BOM · 인코딩이 부모와 다른 파일 0** · 충돌 표식 0줄 · class 이름이 다른 Unit 파일 **0** |
### 알게 된 것 · 남긴 것
- **충돌 난 16개 파일에서는 `뒤이은 수정` 의 글도 함께 사라진다.** 그 줄들을 전부 Accept Theirs(되돌리는 쪽)로 골랐기 때문이다 — 고른 대로다.
뒤 커밋의 글을 지키려면 그 줄만 Take Mine 으로 고르면 된다.
- 자동 조작 쪽: 첫 확인에서 파일 단위 Accept Theirs 가 15개 중 1개만 풀었다(목록 선택이 앱에 안 닿음 - 7차 C-2 와 같은 증상).
충돌이 0 이 될 때까지 되풀이하도록 스크립트를 고쳐 다시 했다. 제품 결함이 아니다.
- 제품 코드는 한 줄도 바꾸지 않았다. 7차 C-2 에서 만든 길이 revert 에서도 그대로 동작했다.
## C-2. cherry-pick 이 원래 작성자를 남기는지 눈으로 (2026-09-16, 완료)
7차 C-2 에서는 시험 저장소의 커밋 작성자가 모두 같아(`시험`) **코드로만** 확인했다.
### 시험 재료 (생성기 `C1Repo`, 같은 씨앗)
`상대 쪽 작업` 커밋만 **다른 사람이 쓴 것**으로 뒀다 — 작성자 `박지훈 <jihoon@localhost>` · 커밋한 사람 `시험 <test@localhost>`.
저장소의 `user.name` 은 그대로 `시험` 이라, 앱이 커밋하면 커밋한 사람은 `시험` 이 된다.
### 확인한 것 (같은 저장소를 새로 만들어, MergeHub 와 git 을 따로)
| 무엇 | 작성자 | 커밋한 사람 |
|---|---|---|
| 가져올 커밋 (`상대 쪽 작업`) | **박지훈** `<jihoon@localhost>` | 시험 |
| **MergeHub** cherry-pick → [커밋] | **박지훈** `<jihoon@localhost>` | 시험 `<test@localhost>` |
| **git** cherry-pick (사본에서 같은 순서) | **박지훈** `<jihoon@localhost>` | 시험 `<test@localhost>` |
| **MergeHub** revert → [커밋] | 시험 `<test@localhost>` | 시험 `<test@localhost>` |
| **git** revert (사본에서) | 시험 `<test@localhost>` | 시험 `<test@localhost>` |
**둘이 같다.** cherry-pick 은 원래 작성자를 남기고 커밋한 사람만 지금 사용자로 바뀐다. revert 는 둘 다 지금 사용자다 — git 과 같은 규칙이다.
이력 목록에도 그 커밋이 `상대 쪽 작업 dddd515 · 박지훈` 으로 보여, 고를 때 누가 쓴 것인지 화면에서 읽힌다.
제품 코드는 바꾸지 않았다.
### 남긴 것
- 자동 조작 쪽: git 으로 revert 를 견줄 때 **MergeHub 가 이미 revert 한 뒤의 저장소를 복제해** git 이 되돌릴 것이 없었다.
저장소를 새로 만들어 git 쪽만 다시 쟀다(위 표의 값).
## C-3. 창 크기 조절에서 안 본 것 (2026-09-16, 완료 · 플랫폼)
7차 E-4 에서 "스냅 · 첫 Win+↓ · 덮는 창 가운데 · 1px 테두리" 네 가지를 남겨 뒀다. 실제 픽셀로 재고, 정할 것은 사용자와 정했다.
**정한 것 (2026-09-16, 사용자)**
- 첫 Win+↓ 는 두 번 누르기 복원과 **같은 크기 · 자리**로.
- 최대화일 때 덮는 창(이름 · 확인 · 잠금 확인)도 **창 가운데**로.
- 보통 크기 창의 1px 테두리 선은 **그대로 둔다**(Windows 가 그리는 선 - 창 경계가 보여 끌기 쉽다).
### 고치기 전에 쟀다 (2560×1600@150% · 1920×1080@100% 두 모니터)
| 확인 | 값 |
|---|---|
| 첫 Win+↓ (기억 없음) | **2400×1350px @(266,266)** — 1600×900 DIP(XAML 기본). 아래로 **16px 화면 밖**, 작업 표시줄도 가림 |
| 이름 창 (최대화 창 2560×1600) | 가운데에서 **세로 36px 위** — 작업 표시줄 높이(72px)의 절반 |
| 이름 창 (보통 크기 창) | 어긋남 0 (이때는 맞았다) |
| Win+← 주 모니터(150%) | 1920×1528px = 1280×1018.7 DIP — 화면 반(1280px)이 아니라 **75%**. 최소 폭 1280 DIP 때문 |
| Win+← 옆 모니터(100%) | 1280×1032px — 반(960px)보다 큼. 같은 까닭 |
| Win+↑ (왼쪽 스냅 상태에서) | 1280×720px — Windows 11 의 네 분할 자리인데 최소 크기라 그만큼 커진다 |
### 고친 것 (플랫폼)
| 파일 | 무엇 |
|---|---|
| `Shell/ShellWindow.xaml.cs` | 최대화로 **들어갈 때** 기억 여부를 잡아 둔다(`normalBeforeMaximize`) — 복원할 때 보면 늦다. 크기 알림이 상태 알림보다 먼저 와서 방금 내려온 기본 크기가 "사용자가 고른 보통 크기" 로 기억돼 버린다. 기억이 없던 복원은 `RestoreTarget(work, useRemembered: false)` 로 **작업 영역 80% · 가운데**. 기억이 있어도 화면 밖으로 걸치면 `KeepInside` 로 끌어들인다 |
| `Shell/OwnerCentering.cs` (새 파일) | 덮는 창을 본 창의 **실제 사각형** 가운데에 놓는다. WPF 의 `CenterOwner` 는 최대화 창의 "복원 자리" 를 기준 삼아 어긋난다. 맞출 창이 없으면(켤 때 이름 창이 셸보다 먼저 뜬다) **모니터 전체** 가운데 — 셸의 최대화가 작업 표시줄까지 덮으므로 그 가운데와 같다 |
| `Settings/UserNameDialog.xaml.cs` · `Messaging/MessageDialog.xaml.cs` · `Locking/LockConfirmDialog.xaml.cs` | 다 그려진 뒤(`ContentRendered`) 위 도우미를 부른다. `Loaded` 때는 높이가 아직 없어(SizeToContent) 그냥 돌아갔다 |
### 확인한 것 (실제 픽셀 · 배포본으로 다시)
| 확인 | 고치기 전 | 고친 뒤 |
|---|---|---|
| 첫 Win+↓ (기억 없음) | 2400×1350 @(266,266) · 화면 밖 16px | **2048×1222 @(256,153)** = 작업 영역 80% · 가운데 · 화면 밖 0 |
| 두 번 누르기 복원 | 작업 영역 80% | 같음 (둘이 같아졌다) |
| 이름 창 · 최대화 창 | 세로 36px 위 | **어긋남 가로 0 · 세로 0** |
| 이름 창 · 보통 크기 창 | 0 | **0** (그대로) |
| 보통 크기로 [종료] → 다시 켜기 | - | 기억 `{256,153,2048,1222,최대화 false}` 대로 뜬다 |
| 화면 이동 | DIP 크기 지킴 | 같음(1280×1019 DIP) |
PlacementTest 37건 통과. 플랫폼 빌드 경고 0 · 오류 0. **배포는 사용자 확인 뒤 `publish-platform.ps1`** 로 했고,
MergeHub 를 다시 빌드해 배포본으로 같은 값을 다시 쟀다(앱 폴더 Core = 배포본 확인).
### 남긴 것 (고치지 않음)
- **스냅은 화면 반쪽이 될 수 없다.** 최소 크기(1280×720 DIP)가 반쪽보다 크기 때문이다 — 주 모니터에서 75%, 옆 모니터에서 67%.
최소 크기를 줄이지 않는 한 그대로다. Windows 11 의 네 분할도 같은 까닭으로 1280×720 이 된다.
- 왼쪽 스냅 상태에서 Win+→ 는 스냅을 풀지 않고 그대로 있었다(잰 두 번 중 한 번은 복원됐다). Windows 쪽 동작이라 두고 본다.
- 1px 테두리 선은 사용자 결정대로 그대로 둔다.
- **화면 잠금은 재지 않았다.** 잠그면 사람이 직접 풀어야 해서 확인이 멈춘다. 잠금 확인 창은 이름 창과 같은 길(`OwnerCentering`)을 쓰므로 함께 맞는다.
## D-1. 웹 문서를 7차 · 8차에 맞게 (2026-09-16, 완료)
`doc/web/index.html` 이 6차에서 멈춰 있었다. 7차 · 8차에서 바뀐 화면과 말을 맞추고, "알아 둘 한계" 를 지금 기준으로 다시 썼다.
### 고친 것
| 어디 | 무엇 |
|---|---|
| 개요(숫자) | 검사 하네스 **22벌 · 1,073건**(948건에서), 로컬 커밋 **94**(75에서), "7차 끝 · 8차 진행 · 네 길 줄끝 바뀐 파일 0". 출처를 `작업지시/8차.md` 로 |
| 매뉴얼 · 켜기 | 이름을 저장하기 전에는 그 창이 닫히지도 움직이지도 않는다(7차 E-3). **창 크기** 문단 추가 — 끌어 조절(최소 1280 × 720) · 두 번 누르기 · <kbd>Win</kbd>+<kbd>↑</kbd>/<kbd>↓</kbd> · 최대화는 작업 표시줄까지 덮음 · 크기 · 모니터 기억 · [화면 이동] 이 크기를 지킴(7차 E-4 · 8차 C-3) |
| 매뉴얼 · 폴더 비교 | 끌어다 놓기 **첫 칸 → 둘째 칸 차례**, 두 칸이 차면 바로 비교(7차 E-2) |
| 매뉴얼 · 네 칸 | 네 칸이 뜨는 경우를 작업별로 — rebase 는 LOCAL 이 올릴 자리 · REMOTE 가 다시 올리는 내 커밋, cherry-pick 은 가져오는 커밋, revert 는 되돌리는 커밋. 3-Way 콤보 자리의 머리 글. **MERGED 번호는 결과 파일 번호**(8차 B-3)와 줄 고른 로그 문구(7차 A-2) |
| 매뉴얼 · 병합 순서 | 마지막 [Save] 뒤 화면이 작업에 맞게 말한다(7차 A-1 · 8차 B-1). **pull · rebase · cherry-pick · revert 도 같은 길** 문단 — 다른 것은 끝내는 단추뿐. 가져올 변경이 없는 cherry-pick 안내(8차 B-2)와 이력 [모든 브랜치](7차 C-2) |
| 매뉴얼 · Git 탭 | 충돌 탭 끝내기 단추가 작업에 따라 병합 커밋 · 계속 · 커밋. 이력 탭에 [모든 브랜치] |
| 매뉴얼 · 알아 둘 한계 | 7차 · 8차에서 사라진 네 줄(주석 자동 풀기가 Merge 에만 · rebase · cherry-pick 미확인 · "3-Way 안 씀" 로그 · 마지막 저장 뒤 "남은 차이")을 빼고, 지금 남은 것으로 — 파일 단위 Accept 는 고른 쪽 줄끝을 그대로 가져온다 · 빠른 비교 · 코드 검사 · **스냅이 반쪽이 안 됨**(8차 C-3) · 로그인 · 권한 |
| 남은 일 | "7차 재료" 표를 **7차에서 고친 것** · **8차에서 고친 것** 두 표로. "6차에서 남긴 것" 을 **8차에 남은 것**(E-1 다섯 길 재확인 · 빈 커밋을 두지 않기로 한 결정)으로 |
| 지금까지 만든 것 | 09-15(7차) · 09-16(8차) 두 줄 추가, 기획 3단계 칸을 6차 → 7차 → 8차로 |
| 발표 자료 | 17장의 "7차: …" 줄을 "7차 · 8차: 다른 충돌 길 · 셸 창 크기 조절 — 끝" 으로 |
| 머리 | 문서 기준 날짜 2026-09-14 → **2026-09-16** |
### 확인한 것
- 화면 문구와 대조: "해결로 저장" · "3-Way 안 씀" · "948건" 같은 옛말이 문서에 하나도 없다(grep).
- 태그 짝 세기: section 26/26 · div 188/188 · table 26/26 · ul 35/35 · ol 11/11 · li 193/193 · tr 212/212 · td 520/520.
- 발행: 같은 주소의 아티팩트를 **버전 7** 로 갱신했다(읽어서 옛 내용을 확인한 뒤 올림). 저장소의 `doc/web/index.html` 과 같은 파일이다.
제품 코드는 바꾸지 않았다.
## F-1. 병합 커밋 메시지 본문에 충돌 해결 내역을 자동으로 적기 (2026-09-17, 추가 요청, 완료)
사용자: "파일단위 머지할때 이력은 그럼 어디남아?" → 제안 중 **병합 커밋 본문에 해결 내역을 자동으로 적기**로 정함.
함께 "스타일 맞추는건 안할거야" — 비교할 때만 C# 스타일을 맞추고 저장은 원래대로 하는 선택지는 만들지 않는다.
### 고치기 전
충돌을 어떻게 풀었는지가 오래 남는 곳이 없었다.
| 어디 | 남는 것 | 한계 |
|---|---|---|
| 소스 | 네 칸에서 줄을 가져오면 `// [이름] 날짜` | 충돌 탭 **파일 단위 Accept** 는 고른 쪽 파일을 바이트째 써서 주석이 없다 |
| git 병합 커밋 | 부모 둘 · 제목 · 작성자 | **본문이 비어 있었다** — 7차 D-1(`fce391f` "본문 없음") · 8차 A-1(`3ba6314`) 에서 잰 대로 |
| Git 탭 로그 | `충돌 해결(Theirs): 경로` | 화면에만 있고 끄면 사라진다(`GitWorkspace.AppendLog` 는 글 속성에만 쌓음) |
| 플랫폼 로그 `D:\UbisamConfig\Log` | `버튼 클릭: Accept Theirs` | 파일 이름도 사람도 없다 |
### 고친 것
| 파일 | 무엇 |
|---|---|
| `Services/MergeResolutionLog.cs` (새 파일) | `MergeResolutionKind`(줄 단위 · Accept Mine · Theirs · Both · 파일 남기기 · 지우기 · 머지 주석 자동). 기록 파일 읽기 · 쓰기(`Parse` · `Record` — 첫 줄 MERGE_HEAD, "종류 탭 경로", 같은 파일은 마지막 것). 본문 만들기(`Body` — "충돌 해결 N개 · 이름", 갈래마다 파일 한 줄씩, 한 갈래 30개 넘으면 "… 외 N개"). 메시지에 붙이기(`WithBody` — 옛 블록은 갈아 끼워 두 번 안 들어가고, 사람이 쓴 본문은 지키고 뒤에 붙인다) |
| `Services/GitService.cs` | `RecordResolution` — 병합 중(MERGE_HEAD)일 때만 `.git/MERGEHUB_RESOLUTIONS` 에 적는다. 못 적어도 푸는 일은 막지 않는다. `GetResolutionBody` · `ResolverName`. 머지 주석 자동 풀기가 적는다. **`CommitMerge` 가 본문을 붙인다** — 사람이 메시지를 고쳤어도 블록은 붙는다(유일한 기록). `ForgetStaleMergeConflicts` 가 기록 파일도 같은 규칙으로 치운다(병합 커밋 · 작업 취소 · 새로고침) |
| `Services/IGitService.cs` | 선언 |
| `Services/GitWorkspace.cs` | 상태를 읽을 때 이름을 넘기고(`Git.ResolverName`) 본문을 `MergeResolutionBody` 로 들고 있는다 |
| `ViewModels/GitViewModel.cs` | 충돌 탭 Accept Mine · Theirs · Both 가 적는다. 병합 메시지를 채울 때 본문을 붙이고, 본문이 바뀌면(충돌을 하나 풀 때마다) **메시지 칸을 새로 채운다** — 사람이 칸을 고쳤으면 두고, 커밋 때 붙는다 |
| `ViewModels/HomeViewModel.cs` | [Save] · Save & Commit 은 "줄 단위", 띠 [파일 남기기] · [파일 지우기] 가 적는다 |
| 하네스 `MergeSaveTest` | 21건 — 기록(첫 줄 · 다른 병합 버림 · 같은 파일 마지막 것 · 역슬래시 · 빈 글), 본문(첫 줄 · 갈래 이름 · 파일마다 한 줄 · 순서 · 없음 · 사람 모름 · 30개 넘음), 메시지(제목 · 빈 줄 · 본문 · 두 번 안 붙음 · 갈아 끼움 · 사람 본문 지킴 · 걷어냄 · CRLF · 제목 없음) |
cherry-pick · revert · rebase 는 원래 커밋 메시지를 쓰므로 이번에는 적지 않는다(MERGE_HEAD 가 없어 `RecordResolution` 이 건너뛴다).
### 확인한 것 (길마다 저장소를 새로 만들어, MergeHub 만으로)
**① 병합을 사람 순서 그대로 끝까지** (파일 단위 15 · 네 칸 7 · 띠 2 · 머지 주석 자동 2)
- [병합 커밋] 전 **Git 탭 메시지 칸에 본문이 미리 보였다.**
- 커밋 `d023a8c` 본문:
```
Merge branch 'feature/theirs' into feature/mine
충돌 해결 26개 · 김승준
줄 단위 (파일 비교에서 골라 Save) 7
Ui/Views/NewPanel.cs … Weld/Unit1.cs
Accept Theirs (상대 쪽 파일 그대로) 15
Common/Util/Unit15.cs … Weld/Unit17.cs
파일 남기기 1
Recipe/ToBeDeletedByMe.cs
파일 지우기 1
Recipe/ToBeDeleted.cs
머지 주석만 달라 자동으로 풂 2
Ui/Dialogs/Unit46.cs
Ui/Views/Unit45.cs
```
- 7 + 15 + 1 + 1 + 2 = **26 = 처음 충돌 수**. 커밋 뒤 `MERGEHUB_RESOLUTIONS` · `MERGEHUB_CONFLICTS` 없음. 줄끝 · BOM 바뀐 파일 0/33 · 충돌 표식 0 · class 이름 검사 0 · 워킹트리 Clean (회귀 없음).
**② 병합 → Accept Mine 두 개 → [작업 취소]**
| 때 | 결과 |
|---|---|
| Accept Mine 뒤 기록 파일 | 첫 줄 MERGE_HEAD, `NoteAuto` 2 · **`Mine Io/Unit12.cs` · `Mine Io/Unit20.cs`** |
| 메시지 칸 | "충돌 해결 4개 · 김승준 / Accept Mine (내 쪽 파일 그대로) 2 / 머지 주석만 달라 자동으로 풂 2" |
| [작업 취소] 뒤 | git 충돌 0 · **기록 파일 없음** |
**③ pull → 전부 파일 단위 Accept Theirs → [병합 커밋]**
- 본문 "`Merge remote-tracking branch 'origin/feature/mine' into feature/mine`" 아래 **충돌 해결 26개** — Accept Theirs 24(지운 파일 둘도 파일 단위로 골랐으므로 여기에) · 머지 주석 자동 2. 기록 파일 없음 · Clean.
하네스 22벌 1,094건 통과(MergeSaveTest 183). 빌드 경고 0 · 오류 0. 설정 파일은 바이트 그대로 되돌림.
### 알아 둘 것
- 병합 커밋 **작성자**는 지금처럼 git `user.name` 이고, 본문의 이름은 MergeHub 의 작업자 이름(설정 [머지 주석] 작성자 → 켤 때 이름 → git `user.name` 순)이다. 둘이 다르면 둘 다 남는다.
- 메시지 칸에서 본문을 지워도 커밋할 때 다시 붙는다 — 파일 단위 Accept 의 유일한 기록이라 뺄 수 없게 했다.
- MergeHub 밖(터미널)에서 푼 충돌은 적히지 않는다. 본문 건수가 처음 충돌 수보다 적으면 그만큼은 밖에서 푼 것이다.
## E-1. 다섯 길을 사람 순서 그대로 다시 끝까지 (2026-09-17, 완료)
지시서대로 **고치지 않고 적기만 했다.** 제품 코드는 한 줄도 안 바꿨다.
### 무엇으로 했나
- 길마다 시험 저장소를 `C1Repo` 로 새로 만들었다. 병합 · pull · rebase · cherry-pick 은 충돌 26개(머지 주석만 다른 2개 포함), revert 는 `feature/revert` 위에서 16개.
- **파일 비교 탭을 미리 열지 않았다** — 충돌 탭의 [3분할로 열기] 로 처음 연다(8차 A-1 을 그대로 밟는 순서). 켤 때 이름 창은 [저장] 으로 닫고, 접힌 원격 영역은 [펴기] 로.
- 처음 돌린 병합 스크립트에 "파일 목록 세기" 단계가 남아 있어 **병합만 탭을 먼저 한 번 열었다.** 그 단계를 스위치로 끄고 병합을 다시 했다(아래 표 ① 은 다시 한 것).
- 푸는 순서는 네 길 같게: 같은 줄 충돌 15개 파일 단위 Accept Theirs → NewPanel Accept Both [아니오] → [3분할로 열기] 뒤 저절로 열리는 파일마다 Theirs · Mine 번갈아 [Save] · 띠 [파일 지우기] · [파일 남기기]. revert 는 큰 파일 하나를 네 칸으로, 나머지 15개를 파일 단위로.
- 확인 값: 커밋 blob 바이트로 BOM · CRLF · LF · UTF-8 을 첫 부모와 견줌, 충돌 표식, `UnitN.cs` 의 class 이름. 설정 `CSharpBraceStyle` 은 길마다 백업 → 끔 → 되돌림(다섯 번 모두 해시 같음).
### 다섯 길의 결과
| 확인 | ① 병합 | ② pull | ③ rebase | ④ cherry-pick | ⑤ revert |
|---|---|---|---|---|---|
| 시작 알림 | 충돌 24건 (머지 주석만 다른 2건은 자동으로 풀림) | 같음 | 같음 + [계속] 안내 | 같음 + [커밋] 안내 | 충돌 16건 + [커밋] 안내 |
| 머리 · 진행 줄 | 병합 진행 중 · 2/26 | 같음 | rebase 1/1 · 남은 충돌 24개 | cherry-pick 진행 중 · 24개 | revert 진행 중 · 16개 |
| [3분할로 열기] 로 처음 연 파일 | NewPanel (고른 파일) | 같음 | 같음 | 같음 | `Motion/Unit0.cs` (고른 파일) |
| 네 칸 REMOTE | feature/theirs | 같음 | 다시 올리는 내 커밋 | 가져오는 커밋 · 작성자 박지훈 | 되돌리는 커밋 |
| 줄 고른 로그 | 18줄 · "3-Way 안 씀" 0 | 같음 | 18줄 · 0 | 18줄 · 0 | 6줄 · 0 |
| 마지막 Save 뒤 파일 비교 탭 | 충돌 정리 끝 · 병합 커밋을 할 수 있습니다 · `… · 병합 전 내 쪽` | 같음 | 충돌 정리 끝 · [계속] 으로 rebase 를 이어 갑니다 · `… · 올릴 자리` | 충돌 정리 끝 · [커밋] 으로 cherry-pick 을 끝냅니다 (N1) | (마지막 파일은 파일 단위) |
| 충돌 남은 채 Save & Commit | 막힘 · git 그대로 | 같음 | 꺼짐 | 꺼짐 | - |
| 끝낸 커밋 | `3725e9c` 부모 둘 | `69214e6` 부모 둘 · Merge remote-tracking branch … | `f2b3b2a` rebase 완료 1/1 | `96cfbc4` 부모 하나 · 원래 메시지 | `650bcd1` Revert "내 쪽 작업" |
| 커밋 본문(8차 F-1) | **충돌 해결 26개 · 김승준** (줄 단위 7 · Theirs 15 · 남기기 1 · 지우기 1 · 주석 자동 2) | **같음 26개** | 해당 없음 | 해당 없음 | 해당 없음(원래 revert 본문) |
| 줄끝 · BOM · 인코딩 바뀐 파일 | **0 / 33** | **0 / 33** | **0 / 31** | **0 / 33** | **0 / 36** |
| 충돌 표식 · class 이름 다른 Unit | 0 · 0 | 0 · 0 | 0 · 0 | 0 · 0 | 0 · 0 |
| 끝난 뒤 | Clean · `.git` 표시 없음 · 기록 파일 없음 | 같음 | Clean · rebase-merge 없음 | Clean · CHERRY_PICK_HEAD 없음 | Clean |
| 빈 cherry-pick (HEAD 를 다시) | - | - | - | [커밋] **꺼짐** · "가져올 변경이 없습니다 - [작업 취소] 로 끝냅니다" · [작업 취소] 로 나옴 | - |
### 판정 기준
| 기준 | 결과 |
|---|---|
| 다섯 길 모두 MergeHub 만으로 끝까지 | **됐다** |
| 줄끝 · BOM 바뀐 파일 0 · 충돌 표식 0 · class 이름 다른 Unit 파일 0 | **다섯 길 모두 0** |
| 7차 A-1 · A-2 · B-1 다시 안 남 | **안 남** — 마지막 Save 뒤 요약이 충돌 탭과 같은 말, "3-Way 안 씀" 로그 0, 커밋 뒤 `MERGEHUB_CONFLICTS` 없음 |
| 8차 A-1 다시 안 남 | **안 남** — 파일 비교 탭을 [3분할로 열기] 로 처음 열어도 고른 파일이 열리고, class 이름 검사 0 |
| 8차 B-1 · B-2 다시 안 남 | **안 남** — rebase "올릴 자리", 빈 cherry-pick [커밋] 꺼짐 |
| 8차 F-1 | 병합 · pull 본문 26개 = 처음 충돌 수, 커밋 뒤 기록 파일 없음 |
### 새로 걸린 것 (고치지 않음 → 9차)
| # | 무엇 | 근거 |
|---|---|---|
| N1 | cherry-pick 마지막 Save 뒤 두 칸의 BASE 는 **HEAD(내 쪽)가 아니라 이력에서 고른 커밋**인데, 요약은 "**내 쪽 대비** 가져온 변경 N줄" 이라고 한다(8차 B-1 에서 넣은 글). 줄 수가 무엇과 견준 것인지 틀리게 읽힌다 | 따로 재 봄: Selected Commit `0c9bd22 "상대 쪽 작업"`(가져온 커밋) · HEAD `85e6806`. 8차 B-1 기록의 "cherry-pick 제목에 꼬리가 없는 것은 맞다" 는 제목만 본 판단이었다 |
| N1-덧 | E-1 cherry-pick 에서 한 번은 제목이 `f310f49 · Weld/Unit1.cs` 로, HEAD(`b7ac29b`)도 가져온 커밋(`68fe17f`)도 아니었다. 줄 수(3줄)로 보면 [모든 브랜치] 목록의 다른 브랜치 커밋(`뒤이은 수정`)으로 보인다 | 같은 순서로 따로 다시 재니 가져온 커밋으로 잡혀 **다시 나지 않았다**. 새로고침 뒤 이력 선택이 어느 커밋으로 돌아가는지 9차에서 원인부터 본다 |
### 시험 도구 쪽 (제품 결함 아님)
- 병합 스크립트의 "파일 목록 세기" 가 파일 비교 탭을 먼저 여는 바람에 조건이 어긋났다 — 스위치(`D7_NO_PREOPEN`)로 끄고 다시 했다.
- 결과 확인 스크립트가 부모 하나인 커밋(rebase · cherry-pick · revert)에서 merge-base 오류를 냈지만 줄끝 판정은 첫 부모와 제대로 했다.
- `Recipe/ToBeDeletedByMe.cs` 를 남기면 git 상태가 `R`(이름 바뀜)로 읽힌다 — git 의 이름 추적이고 커밋 결과는 맞다(7차 D-1 과 같음).
코드는 바꾸지 않았으므로 검사는 그대로(하네스 22벌 1,094건) · 빌드 경고 0 · 오류 0.