6차 B-2: 파일을 바꿀 때 확인 창과 저장이 고친 파일을 가리킨다
Io/Unit12.cs 를 고치고 콤보에서 Io/Unit20.cs 를 고르면 확인 창이 "Unit20.cs 에 저장하지 않은 편집" 이라고 했다. [취소] 뒤에는 콤보가 Io/Unit20.cs 를, 화면은 Io/Unit12.cs 를 보여 서로 달랐다. 확인하다 더 큰 것을 찾았다. [저장하고 계속] 이 새로 고른 파일에 썼다. Io/Unit20.cs 를 고치고 Io/Unit12.cs 로 옮기며 누르자 Io/Unit12.cs 안에 class Unit20 이 들어가고 해결된 것으로 스테이징됐다. 병합 결과가 망가지는 버그다. 원인은 하나다. 콤보에서 고르면 SelectedFile 이 먼저 새 파일로 바뀐 뒤에 변경 처리가 불리는데, 확인 창의 이름과 저장할 곳을 둘 다 SelectedFile 에서 가져왔다. - ConfirmDiscard: 이름을 화면에 실린 파일(_lastLoadedFile)에서. Git 모드는 저장소 안 경로로 - SaveWorkingCopy: 쓸 곳도 실린 파일로. 충돌이면 그 파일의 충돌을 푼다 - 취소 뒤 되돌리기를 콤보의 선택 처리가 끝난 다음 차례에 - 저장소가 이미 열려 있으면 생성자에서 목록을 세운다(B-1 빈틈 - 저장소를 먼저 열고 파일 비교 탭을 나중에 열면 목록이 0개였다) 화면 확인 18건 통과(목록 23개, 이름, 취소, 저장하지 않고 계속, 저장하고 계속 뒤 Unit20 은 풀리고 Unit12 는 그대로). 경고 0, 오류 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9b597fc50f
commit
c76e3d7aee
@ -371,3 +371,58 @@ A-2 · A-4 에서는 저장한 뒤에만 기다렸다 다시 세우게 했고,
|
|||||||
화면 확인 **17건 통과**(Enter 1건은 처음에 목록 아래쪽 행을 골랐다가 자동 조작이 못 찾아 실패 - 가상화된 목록이라 화면 밖 행은
|
화면 확인 **17건 통과**(Enter 1건은 처음에 목록 아래쪽 행을 골랐다가 자동 조작이 못 찾아 실패 - 가상화된 목록이라 화면 밖 행은
|
||||||
안 만들어진다. 위쪽 행으로 다시 해 통과). 이번에 고친 파일은 검사 하네스가 쓰지 않아 앞의 785건이 그대로 유효하다.
|
안 만들어진다. 위쪽 행으로 다시 해 통과). 이번에 고친 파일은 검사 하네스가 쓰지 않아 앞의 785건이 그대로 유효하다.
|
||||||
빌드 경고 0 · 오류 0.
|
빌드 경고 0 · 오류 0.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## B-2. 확인 창이 엉뚱한 파일 이름을 댄다 (2026-09-14, 완료)
|
||||||
|
|
||||||
|
### 고치기 전에 다시 났다
|
||||||
|
|
||||||
|
새로 만든 저장소(충돌 23개)에서 `Io/Unit12.cs` 를 3분할로 열어 Take Theirs 로 고친 뒤, 파일 콤보에서 `Io/Unit20.cs` 를 **마우스로** 골랐다.
|
||||||
|
|
||||||
|
| 본 것 | 값 |
|
||||||
|
|---|---|
|
||||||
|
| 확인 창 첫 줄 | "**Unit20.cs** 에 저장하지 않은 편집이 있습니다." — 고친 것은 Unit12.cs |
|
||||||
|
| [취소] 뒤 콤보 | **`Io/Unit20.cs`** — 새 파일을 가리킨 채 |
|
||||||
|
| [취소] 뒤 화면 | `(merge base) Io/Unit12.cs`, 고친 내용 그대로 — **콤보와 화면이 서로 다르다** |
|
||||||
|
|
||||||
|
(자동 조작은 콤보 항목을 UIA 로 고르지 않고 진짜 마우스로 눌렀다. UIA 로 고르면 확인 창이 뜨는 순간 그 호출이 안 돌아와 앱이 굳는다 - 5차 C-1 에서 겪었다.)
|
||||||
|
|
||||||
|
### 확인하다 찾은 것 둘
|
||||||
|
|
||||||
|
**① [저장하고 계속] 이 엉뚱한 파일에 썼다 — 이것이 가장 컸다.**
|
||||||
|
`Io/Unit20.cs` 를 고치고 `Io/Unit12.cs` 로 옮기며 [저장하고 계속] 을 눌렀다. 충돌은 23 → 22 로 줄었는데 `Io/Unit20.cs` 는 여전히 `UU` 였다.
|
||||||
|
저장소를 들여다보니 **`Io/Unit12.cs` 안에 `class Unit20` 이 들어가 있었고, 해결된 것(`M`)으로 스테이징돼 있었다.**
|
||||||
|
고친 파일의 글이 다른 파일을 덮어쓰고, 덮인 파일은 풀린 것으로 처리됐다. 병합 결과가 망가지는 버그다.
|
||||||
|
|
||||||
|
**② B-1 의 빈틈 — 저장소를 먼저 열고 파일 비교 탭을 처음 열면 목록이 끝내 0개.**
|
||||||
|
B-1 확인 때는 늘 파일 비교 탭을 먼저 열어 두었다. 순서를 바꾸자 파일 콤보가 0개였다.
|
||||||
|
그 화면의 자동 열기는 이미 열린 저장소면 아무것도 안 하고, 새로고침 신호는 화면이 생기기 전에 지나갔다.
|
||||||
|
|
||||||
|
### 무엇이 원인이었나
|
||||||
|
|
||||||
|
모두 한 뿌리다. 파일 콤보에서 다른 파일을 고르면 **`SelectedFile` 이 먼저 새 파일로 바뀐 뒤에** 변경 처리가 불린다.
|
||||||
|
그 안에서 뜨는 확인 창이 이름을 `SelectedFile` 에서 가져왔고, [저장하고 계속] 의 저장(`SaveWorkingCopy`)도 쓸 곳을 `SelectedFile` 에서 가져왔다.
|
||||||
|
[취소] 뒤 되돌리기는 콤보가 고르는 **도중에** 값을 되돌려, 콤보가 그 알림을 흘려 버렸다.
|
||||||
|
|
||||||
|
### 고친 것
|
||||||
|
|
||||||
|
| 자리 | 무엇 |
|
||||||
|
|---|---|
|
||||||
|
| `ConfirmDiscard` | 이름을 **지금 화면에 실린 파일**(`_lastLoadedFile`)에서 가져온다. Git 모드는 저장소 안 경로로 적는다 - 다른 폴더에 같은 이름 파일이 흔하다 |
|
||||||
|
| `SaveWorkingCopy` | 쓸 곳도 **실린 파일**로. 병합 중 충돌 파일이면 그 파일의 충돌을 푼다 |
|
||||||
|
| `OnSelectedFileChanged` | [취소] 의 되돌리기를 **콤보의 선택 처리가 끝난 다음 차례**에 한다 |
|
||||||
|
| 생성자 | 저장소가 이미 열려 있으면 그 저장소로 목록을 세운다(B-1 빈틈) |
|
||||||
|
|
||||||
|
### 확인한 것 (새로 만든 저장소, 저장소를 먼저 열고 파일 비교 탭을 나중에 처음 연다)
|
||||||
|
|
||||||
|
| 확인 | 결과 |
|
||||||
|
|---|---|
|
||||||
|
| 파일 비교 탭을 처음 연다, [새로고침] 안 누름 | 목록 **23개** |
|
||||||
|
| 고친 `Io/Unit12.cs` 에서 `Io/Unit20.cs` 를 고름 | "**Io/Unit12.cs** 에 저장하지 않은 편집이 있습니다. / 다른 파일을 엽니다: Io/Unit20.cs" |
|
||||||
|
| [취소] | 콤보 `Io/Unit12.cs`, 화면 `(merge base) Io/Unit12.cs`, 고친 내용 그대로 |
|
||||||
|
| [저장하지 않고 계속] | 콤보·화면 `Io/Unit20.cs`, git 충돌 23 그대로, `Io/Unit12.cs` 는 여전히 `UU` |
|
||||||
|
| `Io/Unit20.cs` 를 고치고 `Io/Unit12.cs` 로 옮기며 [저장하고 계속] | 확인 창이 **Io/Unit20.cs** 이름을 댐. git 충돌 22, **풀린 것은 `Io/Unit20.cs`**(`M`, 안의 형식 `Unit20`, 상대 줄 들어감), **`Io/Unit12.cs` 는 `UU` 그대로**(안의 형식 `Unit12`), 그다음 `Io/Unit12.cs` 가 열림 |
|
||||||
|
|
||||||
|
화면 확인 **18건 통과**. 고친 파일(`HomeViewModel`)은 검사 하네스가 쓰지 않아 앞의 785건이 그대로 유효하다. 빌드 경고 0 · 오류 0.
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
| 날짜 | 항목 | 커밋 |
|
| 날짜 | 항목 | 커밋 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| 2026-09-14 | **6차 B-2** — 파일을 바꿀 때 확인 창이 고친 파일 이름을 대고, [저장하고 계속] 이 엉뚱한 파일(새로 고른 파일)에 쓰던 것을 막음. [취소] 뒤 콤보가 제자리로. 저장소를 먼저 열면 목록이 0개이던 B-1 빈틈도 | 아래 |
|
||||||
| 2026-09-14 | **6차 B-1** — 새로고침 뒤 파일 목록을 게이트가 풀릴 때까지 기다렸다 세움(병합 뒤 304개 → 23개). 충돌 목록 두 번 누르기·Enter·[3분할로 열기] 로 파일 비교 탭 네 칸에서 연다. 없는 '홈 탭' 글을 고침 | 아래 |
|
| 2026-09-14 | **6차 B-1** — 새로고침 뒤 파일 목록을 게이트가 풀릴 때까지 기다렸다 세움(병합 뒤 304개 → 23개). 충돌 목록 두 번 누르기·Enter·[3분할로 열기] 로 파일 비교 탭 네 칸에서 연다. 없는 '홈 탭' 글을 고침 | 아래 |
|
||||||
| 2026-09-14 | **6차 A-5** — 파일 단위 Accept Both 가 두 벌을 글로 풀어 이어 붙이고 내 쪽 형식으로 쓴다(가운데 BOM 사라짐). 누르기 전에 무엇이 일어나는지 묻는다. A 묶음 끝 | 아래 |
|
| 2026-09-14 | **6차 A-5** — 파일 단위 Accept Both 가 두 벌을 글로 풀어 이어 붙이고 내 쪽 형식으로 쓴다(가운데 BOM 사라짐). 누르기 전에 무엇이 일어나는지 묻는다. A 묶음 끝 | 아래 |
|
||||||
| 2026-09-14 | **6차 A-4** — 한쪽이 지운 충돌(UD·DU)은 줄 단위 3분할 대신 남은 파일을 두 칸으로 보이고 [파일 남기기] · [파일 지우기] 로 푼다. 거꾸로 세던 범례(Theirs only 89)가 없어짐 | 아래 |
|
| 2026-09-14 | **6차 A-4** — 한쪽이 지운 충돌(UD·DU)은 줄 단위 3분할 대신 남은 파일을 두 칸으로 보이고 [파일 남기기] · [파일 지우기] 로 푼다. 거꾸로 세던 범례(Theirs only 89)가 없어짐 | 아래 |
|
||||||
|
|||||||
@ -104,7 +104,7 @@
|
|||||||
| 상태 | 항목 |
|
| 상태 | 항목 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **완료** | B-1 충돌 목록에서 3분할 화면까지 가는 길이 끊겨 있다 — 병합 뒤 목록이 바로 서고, 두 번 누르기·Enter·[3분할로 열기] |
|
| **완료** | B-1 충돌 목록에서 3분할 화면까지 가는 길이 끊겨 있다 — 병합 뒤 목록이 바로 서고, 두 번 누르기·Enter·[3분할로 열기] |
|
||||||
| 대기 | B-2 확인 창이 엉뚱한 파일 이름을 댄다 |
|
| **완료** | B-2 확인 창이 엉뚱한 파일 이름을 댄다 — 이름·[저장하고 계속] 모두 실린 파일 기준, [취소] 뒤 콤보도 돌아온다 |
|
||||||
| 대기 | B-3 커밋 메시지가 엉뚱하게 남는다 |
|
| 대기 | B-3 커밋 메시지가 엉뚱하게 남는다 |
|
||||||
| 대기 | B-4 MERGED 칸 줄 번호가 네 자리에서 잘린다 |
|
| 대기 | B-4 MERGED 칸 줄 번호가 네 자리에서 잘린다 |
|
||||||
| 대기 | B-5 머지 주석은 소스에 넣고, 병합 뒤에는 그 줄을 무시한다 |
|
| 대기 | B-5 머지 주석은 소스에 넣고, 병합 뒤에는 그 줄을 무시한다 |
|
||||||
|
|||||||
@ -69,6 +69,15 @@ namespace MergeHub.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Git 탭에서 저장소를 이미 연 뒤에 이 화면이 처음 만들어진 경우(6차 B-2 를 확인하다 찾은 B-1 의 빈틈).
|
||||||
|
// 아래 자동 열기는 이미 열린 저장소면 아무것도 안 하고, 새로고침 신호는 이 화면이 생기기 전에 지나갔다.
|
||||||
|
// 그래서 파일 목록이 끝내 0개로 남았다. 지금 저장소로 목록을 세운다.
|
||||||
|
if (_workspace.IsRepositoryOpen)
|
||||||
|
{
|
||||||
|
OnWorkspaceRefreshed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 설정에 기본 저장소가 있으면 바로 열어서 첫 화면부터 내용이 보이게 한다.
|
// 설정에 기본 저장소가 있으면 바로 열어서 첫 화면부터 내용이 보이게 한다.
|
||||||
// 저장소가 아니면 설정에 적어 둔 두 파일로 비교 화면을 만든다 - Git 없이도 쓰는
|
// 저장소가 아니면 설정에 적어 둔 두 파일로 비교 화면을 만든다 - Git 없이도 쓰는
|
||||||
// 도구라는 것을 첫 화면에서 바로 보여 준다. 둘을 동시에 걸면 안 된다.
|
// 도구라는 것을 첫 화면에서 바로 보여 준다. 둘을 동시에 걸면 안 된다.
|
||||||
@ -355,10 +364,16 @@ namespace MergeHub.ViewModels
|
|||||||
|
|
||||||
if (!ConfirmDiscard($"다른 파일을 엽니다: {value}"))
|
if (!ConfirmDiscard($"다른 파일을 엽니다: {value}"))
|
||||||
{
|
{
|
||||||
|
// 되돌리기는 <b>콤보의 선택 처리가 끝난 다음 차례</b>에 한다(6차 B-2).
|
||||||
|
// 이 자리는 콤보가 고르는 도중이라, 여기서 바로 값을 되돌리면 콤보가 그 알림을 흘려 버린다.
|
||||||
|
// [취소] 를 눌렀는데 콤보는 새 파일(Io/Unit20.cs)을, 화면은 고치던 파일(Io/Unit12.cs)을 보이며 서로 달랐다.
|
||||||
var back = _lastLoadedFile;
|
var back = _lastLoadedFile;
|
||||||
_revertingFile = true;
|
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
|
||||||
try { SelectedFile = back; }
|
{
|
||||||
finally { _revertingFile = false; }
|
_revertingFile = true;
|
||||||
|
try { SelectedFile = back; }
|
||||||
|
finally { _revertingFile = false; }
|
||||||
|
}), DispatcherPriority.Background);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2349,9 +2364,13 @@ namespace MergeHub.ViewModels
|
|||||||
if (_suspendGuard) return true;
|
if (_suspendGuard) return true;
|
||||||
if (!HasChanges) return true;
|
if (!HasChanges) return true;
|
||||||
|
|
||||||
var name = IsPlainMode
|
// <b>고친 파일</b>의 이름을 댄다(6차 B-2). 파일을 바꿀 때는 이 창이 뜨는 순간 SelectedFile 이 이미 새 파일이라,
|
||||||
? (string.IsNullOrWhiteSpace(RightFile) ? "지금 파일" : Path.GetFileName(RightFile))
|
// 예전에는 그 새 파일 이름을 댔다 - Motion/Unit0.cs 를 고쳤는데 "ToBeDeleted.cs 에 저장하지 않은 편집" 이라고 했다.
|
||||||
: (string.IsNullOrWhiteSpace(SelectedFile) ? "지금 파일" : Path.GetFileName(SelectedFile));
|
// Git 모드는 저장소 안 경로로 적는다. 다른 폴더에 같은 이름 파일이 흔하다.
|
||||||
|
var editing = IsPlainMode ? RightFile : (_lastLoadedFile ?? SelectedFile);
|
||||||
|
var name = string.IsNullOrWhiteSpace(editing)
|
||||||
|
? "지금 파일"
|
||||||
|
: IsPlainMode ? Path.GetFileName(editing) : editing;
|
||||||
|
|
||||||
var choice = MessageUtil.ShowChoice(
|
var choice = MessageUtil.ShowChoice(
|
||||||
"저장하지 않은 편집",
|
"저장하지 않은 편집",
|
||||||
@ -2377,12 +2396,17 @@ namespace MergeHub.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool SaveWorkingCopy()
|
private bool SaveWorkingCopy()
|
||||||
{
|
{
|
||||||
|
// <b>지금 화면에 실려 있는 파일</b>에 쓴다(6차 B-2). 파일을 바꾸다 이 확인 창이 떴을 때는 SelectedFile 이
|
||||||
|
// 이미 새 파일이다. 예전에는 그 새 파일에 썼다 - Io/Unit20.cs 를 고치고 Io/Unit12.cs 로 옮기며
|
||||||
|
// "저장하고 계속" 을 누르자 <b>Unit20 의 글이 Unit12 에 써지고 Unit12 가 해결된 것으로 스테이징됐다.</b>
|
||||||
|
var loaded = IsPlainMode ? null : (_lastLoadedFile ?? SelectedFile);
|
||||||
|
|
||||||
var target = IsPlainMode
|
var target = IsPlainMode
|
||||||
? RightFile
|
? RightFile
|
||||||
: string.IsNullOrEmpty(SelectedFile)
|
: string.IsNullOrEmpty(loaded)
|
||||||
? string.Empty
|
? string.Empty
|
||||||
: Path.Combine(_workspace.RepositoryPath,
|
: Path.Combine(_workspace.RepositoryPath,
|
||||||
SelectedFile!.Replace('/', Path.DirectorySeparatorChar));
|
loaded!.Replace('/', Path.DirectorySeparatorChar));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(target))
|
if (string.IsNullOrWhiteSpace(target))
|
||||||
{
|
{
|
||||||
@ -2396,7 +2420,7 @@ namespace MergeHub.ViewModels
|
|||||||
|
|
||||||
// 병합 중 충돌 파일을 워킹트리에만 쓰면 git 은 여전히 충돌로 본다. 충돌 표시는 사라졌는데
|
// 병합 중 충돌 파일을 워킹트리에만 쓰면 git 은 여전히 충돌로 본다. 충돌 표시는 사라졌는데
|
||||||
// 인덱스는 풀리지 않은 어정쩡한 상태가 된다. [해결로 저장] 과 같은 길로 보낸다(6차 A-2).
|
// 인덱스는 풀리지 않은 어정쩡한 상태가 된다. [해결로 저장] 과 같은 길로 보낸다(6차 A-2).
|
||||||
var conflictPath = IsPlainMode ? null : SelectedFile;
|
var conflictPath = loaded;
|
||||||
if (conflictPath is not null && _workspace.IsMergeInProgress &&
|
if (conflictPath is not null && _workspace.IsMergeInProgress &&
|
||||||
_workspace.Git.GetConflicts().Any(c => c.Path == conflictPath))
|
_workspace.Git.GetConflicts().Any(c => c.Path == conflictPath))
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user