10차 B-1: Git 탭과 파일 비교 탭이 고른 커밋을 서로 바로 따라간다
두 탭이 같은 고른 커밋 값을 쓰는데 표시는 새로고침 전까지 안 따라왔다. 파일 비교 탭에서 '바탕' 을 고르면 Git 탭은 '내 쪽 작업' 에 선택 표시가 남은 채 [Revert] 가 '바탕' 을 되돌렸다. 사용자 결정: 바로 따라간다(양방향) · 저장 안 한 편집이 있으면 고르는 순간 묻는다. - GitWorkspace: CommitChosen 알림, ConfirmLeaveCommit(null 안 물음 / true 계속 / false 취소) - CommitSelection.IsOtherCommit (하네스 +4, MergeSaveTest 210) - HomeViewModel: 다른 쪽이 고르면 게이트가 빈 뒤 목록 · 두 칸을 다시 세움, WillAskBeforeDiscard - GitViewModel: 파일 비교 탭이 고르면 선택 표시 · 단추 따라감, 커밋 내용은 탭이 다시 보일 때 - GitView: 이력 목록이 선택을 바꾸기 전에(마우스 · 방향키) 묻고 [취소] 면 누름을 막음, 물은 뒤 [계속] 이면 직접 고름 확인: 두 방향 · BASE 까지 따라감, 편집 있음 [취소] 두 탭 제자리 · 창 한 번, [계속] 따라감 · 편집 버려짐, 방향키 같음, [Revert] 는 보이는 커밋, 9차 A-2 흐름 그대로. 22벌 1,126건 통과, 빌드 경고 0 오류 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
313acb596a
commit
5eaf6011dd
@ -53,3 +53,62 @@
|
||||
|
||||
- 첫 병합 · 9차 간격 묶음이 8회차에서 UI 자동화 조회 오류(`ElementNotAvailableException`, 화면 요소 훑기 중)로 끊겼다. 모자란 만큼 14회를 더 돌렸다.
|
||||
- 되풀이 스크립트 매개변수 `$Tag` 가 `WithSettings` 의 `$tag` 와 겹쳐(PowerShell 은 대소문자를 가리지 않는다) `$Label` 로 바꿨다 — 9차 A-2 와 같은 실수.
|
||||
|
||||
## B-1. Git 탭 이력에서 고른 커밋을 파일 비교 탭이 새로고침 전까지 따라오지 않는다 (2026-09-17, 완료)
|
||||
|
||||
사용자 결정(2026-09-17): **바로 따라간다(양방향)** · 파일 비교 탭에 저장 안 한 편집이 있으면 **고르는 순간 묻는다**.
|
||||
("두 탭을 따로 둔다" · "따라가지 않고 알린다" 는 고르지 않음.)
|
||||
|
||||
### 고치기 전에 다시 났다 (새로 만든 저장소)
|
||||
|
||||
| 순서 | 결과 |
|
||||
|---|---|
|
||||
| Git 탭 이력에서 `바탕` 을 고름 | Git 탭은 `바탕`. 파일 비교 탭은 위 줄 Selected Commit · 왼쪽 이력 선택 · BASE 제목 모두 **`내 쪽 작업` 그대로** |
|
||||
| 파일 비교 탭 [새로고침] | 그제야 `바탕` 으로 따라옴 |
|
||||
| **반대로** 파일 비교 탭 이력에서 `바탕` 을 고름 | Git 탭 이력은 **`내 쪽 작업` 에 선택 표시가 남음** |
|
||||
| 그 상태에서 Git 탭 [Revert] | 로그 "revert 시작: `바탕`" — **화면에 선택돼 보이는 `내 쪽 작업` 이 아니라 `바탕` 을 되돌림**, 충돌 34건(시험 저장소, 뒤에 버림) |
|
||||
|
||||
반대 방향이 더 위험했다 — 화면에 보이는 것과 다른 커밋에 Git 작업(Revert · Cherry-pick · Reset)이 걸린다.
|
||||
|
||||
### 원인
|
||||
|
||||
- 두 탭은 같은 값(`GitWorkspace.SelectedCommit`)을 쓰지만, 고른 쪽 뷰모델만 화면을 바꾸고 다른 쪽은 **새로고침 알림(`Refreshed`)** 으로만 다시 읽었다.
|
||||
|
||||
### 고친 것
|
||||
|
||||
- `GitWorkspace` — `CommitChosen` 알림(고른 쪽을 인자로)과 `ConfirmLeaveCommit`(파일 비교 화면이 앉히는 확인. 답: null 물을 편집 없음 · true 물었고 계속 · false [취소]).
|
||||
- `CommitSelection.IsOtherCommit` — 사람이 **다른 커밋**을 고른 것인지(목록이 비워지며 들어온 null · 같은 해시의 새 객체는 아님). 하네스 `MergeSaveTest` 4건(210건).
|
||||
- `HomeViewModel` — 파일 비교 탭에서 고르면 `CommitChosen` 을 내고, 다른 쪽이 고르면 왼쪽 이력 · Selected Commit · 두 칸을 **게이트가 빈 뒤에** 다시 세운다(`RebuildListAfterRefreshAsync`).
|
||||
확인 창을 띄울지(`WillAskBeforeDiscard`)를 `ConfirmDiscard` 에서 떼어 둘이 같은 조건을 쓴다.
|
||||
- `GitViewModel` — 고르면 `CommitChosen`. 파일 비교 탭이 고르면 이력 선택 표시 · 단추가 따라가고, **커밋 내용(diff)은 Git 탭이 다시 보일 때** 그린다(`ShowPendingDiff`).
|
||||
- `GitView` — 이력 목록(`HistoryList`)이 **선택을 바꾸기 전에**(마우스 누름 · ↑↓ Home End PageUp PageDown) 묻는다. [취소] 면 그 누름을 막고, 물은 뒤 [계속] 이면 화면이 그 커밋을 직접 고른다.
|
||||
|
||||
### 고치며 걸린 것 (최종 모양에 이른 까닭)
|
||||
|
||||
| 해 본 것 | 걸린 것 |
|
||||
|---|---|
|
||||
| 다른 쪽이 고르면 바로 `LoadCommitAsync` | Git 탭이 커밋 내용을 그리느라 작업 게이트를 쥐고 있어 파일 비교 탭 읽기가 **건너뛰어짐** — Selected Commit 만 바뀌고 BASE 는 옛 커밋 |
|
||||
| 선택 바인딩 setter 안에서 확인 창 | 창이 닫힌 뒤 목록이 선택을 다시 밀어 넣어 **[취소] 해도 창이 한 번 더** 뜸 |
|
||||
| setter 에서 미뤄 묻고 [취소] 면 변경 알림 · `SelectedItem` 다시 넣기 · `SetCurrentValue`(ContextIdle) | 코드상 `SelectedItem` 은 돌아오는데 **목록은 `바탕` 을 선택으로 남김**(UI 자동화 SelectionPattern · 화면 모두). `SelectedItem = …` 은 바인딩을 떼어 내기까지 함 |
|
||||
| **선택이 바뀌기 전에** 묻고 누름을 막음 | [취소] 는 맞음. 그런데 [계속] 이어도 **창이 누름을 끊어 목록이 고르지 않음** → 물었으면 화면이 직접 고르게 해서 끝 |
|
||||
|
||||
### 확인한 것 (고친 앱, 사람 길 — 목록은 마우스 누름 · 방향키, `d10-b1-after.ps1` · `d10-b1-cancel.ps1` · `d10-b1-diff.ps1`)
|
||||
|
||||
| 경우 | 결과 |
|
||||
|---|---|
|
||||
| Git 탭에서 `바탕` | 파일 비교 탭 Selected Commit · 왼쪽 이력 · **BASE 제목까지** `바탕` |
|
||||
| 파일 비교 탭에서 `내 쪽 작업` | Git 탭 이력 선택 `내 쪽 작업` |
|
||||
| 편집 있음 · Git 탭에서 `바탕` 누름 → [취소] | 창 한 번(“Common/Util/Unit103.cs 에 저장하지 않은 편집이 있습니다. 다른 커밋을 봅니다.”) · 두 탭 · 목록 자체(SelectionPattern) 모두 `내 쪽 작업` · 다시 뜨는 창 없음 |
|
||||
| 편집 있음 · `바탕` 누름 → [저장하지 않고 계속] | 두 탭 `바탕` · 워킹트리 바뀐 파일 0(편집 버려짐) |
|
||||
| 편집 있음 · 같은 커밋 누름 | 창 안 뜸 |
|
||||
| 편집 있음 · ↑ → [취소] / ↑ → [계속] | 그대로 `바탕` / 두 탭 `내 쪽 작업` |
|
||||
| 파일 비교 탭에서 `내 쪽 작업` → Git 탭 [Revert] | 로그 "revert 시작: `내 쪽 작업`" — **보이는 커밋** |
|
||||
| 파일 비교 탭에서 `바탕` → Git 탭으로 옴 | Git 탭 커밋 내용 머리 `… 바탕` |
|
||||
| 9차 A-2 흐름(cherry-pick 1회, `d9-a2.ps1`) | 시작 · 파일 단위 = 고른 커밋 · Save 뒤 = HEAD · 커밋 뒤 = 새 HEAD — **맞음** |
|
||||
|
||||
- 하네스 22벌 1,126건 통과(+4) · 빌드 경고 0 · 오류 0. 임시 로그(`[B1측정]`)는 모두 걷어냄(남은 줄 0).
|
||||
|
||||
### 남긴 것
|
||||
|
||||
- UI 자동화의 `SelectionItemPattern.Select()` 처럼 **마우스 · 키보드를 거치지 않고** 목록 선택을 바꾸면 묻지 않고 따라간다(사람 길이 아님).
|
||||
- 처음 켰을 때 Git 탭 커밋 내용 칸이 비어 있는 것은 전부터 그렇다(이력에서 고르면 그려진다).
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
| 날짜 | 항목 | 커밋 |
|
||||
|---|---|---|
|
||||
| 2026-09-17 | **10차 B-1** — Git 탭과 파일 비교 탭이 고른 커밋 값을 함께 쓰는데 표시는 새로고침 전까지 서로 안 따라왔다. 파일 비교 탭에서 고르면 Git 탭은 옛 커밋에 선택 표시가 남은 채 **[Revert] 가 보이지 않는 커밋에 걸렸다.** 사용자 결정대로 양방향으로 바로 따라가고(`CommitChosen`), 파일 비교 탭에 저장 안 한 편집이 있으면 Git 탭 목록이 선택을 바꾸기 전에 물어 [취소] 면 누름을 막는다. 하네스 +4 | 아래 |
|
||||
| 2026-09-17 | **10차 A-1** — 9차 D-1 N1(네 칸에서 고르기 한 번이 안 남아 멈춤)을 앱 안 임시 로그(잰 뒤 되돌림)와 함께 61회 · 누름 366번(병합 · cherry-pick × 9차 간격 · 0.1초) 되풀이 — 다시 안 남, 앱은 Take 372번 모두 충돌 줄에서 받아 하나씩 줄임(헛돈 0). Take 뒤 [다음 충돌] 처리 전에는 Take 단추가 꺼져 있는데 9차 시험 도구가 "꺼져서 안 누름" 을 버린 것으로 보임. 제품 코드 변경 없음, 시험 도구가 다시 누르고 못 누르면 적게 고침 | 아래 |
|
||||
| 2026-09-17 | **10차 지시서** — 9차 전부 끝. D-1 에서 새로 걸린 N1(A-1 네 칸에서 고르기 한 번이 남지 않아 멈춤 — 자동 조작인지 제품인지 원인부터)과 9차에서 적어 둔 셋(B-1 Git 탭에서 고른 커밋을 파일 비교 탭이 안 따라옴 — 먼저 정함 · C-1 머지 주석 무시를 끈 채 다시 정렬하면 반영 색이 옆 줄로 · D-1 첫 폴더 비교 9.2초 — 재고 정함) · E-1 다섯 길 + pull · E-2 웹 문서. 코드 변경 없음 | 아래 |
|
||||
| 2026-09-17 | **9차 D-1** — 병합 · rebase · cherry-pick · revert 를 새 저장소에서 파일 비교 탭을 미리 열지 않고 끝까지(코드 변경 없음). cherry-pick · revert 는 [모든 브랜치] 를 켜고 마지막 파일을 네 칸으로. 네 길 모두 마지막 Save 뒤 제목 · 요약 · 기준(HEAD) 같음 · 요약 N줄 = git diff · 커밋 뒤 기준 새 HEAD · 줄끝 · BOM 바뀐 파일 0 · class 검사 0. 새로 걸린 것: N1 cherry-pick 첫 회차에서 고르기 한 번이 안 남아 "남은 충돌 1개" 로 멈춤(다시 하니 끝까지) → 10차. **9차 전부 끝**. 웹 문서 "9차 끝" (아티팩트 버전 10) | 아래 |
|
||||
|
||||
@ -292,7 +292,7 @@
|
||||
|
||||
| 상태 | 항목 |
|
||||
|---|---|
|
||||
| 대기 | B-1 Git 탭 이력에서 고른 커밋을 파일 비교 탭이 새로고침 전까지 따라오지 않는다 (먼저 사용자와 정함) |
|
||||
| **완료** | B-1 Git 탭 이력에서 고른 커밋을 파일 비교 탭이 새로고침 전까지 따라오지 않는다 — 사용자가 "바로 따라간다 · 편집 있으면 고르는 순간 묻는다" 를 고름. 반대 방향(파일 비교 탭에서 고름)은 Git 탭 선택 표시가 남아 [Revert] 가 보이지 않는 커밋에 걸렸다. 양쪽이 고른 것을 알리고 다른 쪽이 따라감(파일 비교는 게이트가 빈 뒤 다시 세움, Git 탭 커밋 내용은 다시 보일 때). 목록이 선택을 바꾸기 전에 묻고 [취소] 면 누름을 막음. 마우스 · 방향키 · [취소] · [계속] · [Revert] 대상 확인 |
|
||||
|
||||
### C. 남은 표시 어긋남
|
||||
|
||||
|
||||
@ -50,6 +50,14 @@ namespace MergeHub.Services
|
||||
public static bool EntersResolvedOperation(bool wasResolved, bool inProgress, int conflictCount) =>
|
||||
IsResolvedOperation(inProgress, conflictCount) && !wasResolved;
|
||||
|
||||
/// <summary>
|
||||
/// 사람이 한 탭(Git 탭 이력 · 파일 비교 탭 이력)에서 <b>다른 커밋</b>을 골랐는가 - 그때만 다른 탭이 따라가고,
|
||||
/// 파일 비교 탭에 저장 안 한 편집이 있으면 먼저 묻는다(10차 B-1).
|
||||
/// 목록을 갈아 끼우며 들어온 null 이나, 새로고침으로 같은 해시의 새 객체가 들어온 것은 고른 것이 아니다.
|
||||
/// </summary>
|
||||
public static bool IsOtherCommit(string? currentSha, string? newSha) =>
|
||||
!string.IsNullOrEmpty(newSha) && !SameSha(currentSha, newSha);
|
||||
|
||||
/// <summary>작업이 진행 중이고 남은 충돌이 없는가.</summary>
|
||||
public static bool IsResolvedOperation(bool inProgress, int conflictCount) => inProgress && conflictCount == 0;
|
||||
|
||||
|
||||
@ -290,6 +290,25 @@ namespace MergeHub.Services
|
||||
/// </summary>
|
||||
public Func<string, bool>? ConfirmDiscardEdits { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 사람이 한 탭의 이력에서 다른 커밋을 골랐다는 알림. 인자는 고른 쪽(뷰모델)이다(10차 B-1).
|
||||
///
|
||||
/// 고른 커밋(<see cref="SelectedCommit"/>)은 Git 탭과 파일 비교 탭이 함께 쓰는데, 예전에는 고른 쪽만 화면을 바꾸고
|
||||
/// 다른 쪽은 새로고침 알림으로만 다시 읽었다. 파일 비교 탭에서 '바탕' 을 고르면 Git 탭은 '내 쪽 작업' 에 선택 표시가 남은 채
|
||||
/// [Revert] 가 '바탕' 을 되돌렸다. 새로고침이 목록을 갈아 끼우며 고르는 것은 이 알림을 내지 않는다(<see cref="Refreshed"/> 가 맡는다).
|
||||
/// </summary>
|
||||
public event Action<object>? CommitChosen;
|
||||
|
||||
public void NotifyCommitChosen(object chooser) => CommitChosen?.Invoke(chooser);
|
||||
|
||||
/// <summary>
|
||||
/// Git 탭에서 다른 커밋을 고르기 전에, 파일 비교 탭에 저장 안 한 편집이 있으면 물어봐 달라고 파일 비교 화면이 앉혀 두는 자리(10차 B-1).
|
||||
/// 파일 비교 탭 자기 이력에서 고를 때와 같은 확인 창이다. 앉은 사람이 없으면 늘 계속한다.
|
||||
/// 답: null = 물을 편집이 없어 창을 띄우지 않음 · true = 물었고 계속 · false = 물었고 [취소].
|
||||
/// 물었는지를 따로 돌려주는 까닭 - 누름 도중에 창이 뜨면 목록이 그 누름을 끝까지 처리하지 않아, 화면이 직접 골라 줘야 한다.
|
||||
/// </summary>
|
||||
public Func<bool?>? ConfirmLeaveCommit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 작업 하나를 실행하고 성공하면 저장소 상태를 다시 읽는다.
|
||||
///
|
||||
|
||||
@ -26,6 +26,17 @@ namespace MergeHub.ViewModels
|
||||
{
|
||||
_workspace = workspace;
|
||||
_workspace.Refreshed += () => OnPropertyChanged(nameof(SelectedCommit));
|
||||
|
||||
// 파일 비교 탭에서 고른 커밋을 이력 선택 표시 · 커밋 내용 · 단추(Revert · Cherry-pick · Reset)가 따라간다(10차 B-1).
|
||||
// 커밋 내용(diff)은 여기서 바로 그리지 않는다 - 파일 비교 탭이 그 커밋의 목록 · 본문을 읽는 중이라,
|
||||
// 같은 작업 게이트를 먼저 잡으면 그쪽 읽기가 건너뛰어진다. 이 탭이 다시 보일 때 그린다.
|
||||
_workspace.CommitChosen += chooser =>
|
||||
{
|
||||
if (ReferenceEquals(chooser, this)) return;
|
||||
OnPropertyChanged(nameof(SelectedCommit));
|
||||
RaiseCanExecuteChanged();
|
||||
_diffPending = true;
|
||||
};
|
||||
_workspace.Refreshed += SyncStashSelection;
|
||||
_workspace.StateChanged += RaiseCanExecuteChanged;
|
||||
_workspace.PropertyChanged += (_, e) =>
|
||||
@ -130,19 +141,54 @@ namespace MergeHub.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>파일 비교 탭에서 커밋을 골라, 이 탭의 커밋 내용이 아직 옛 커밋 것인지(10차 B-1).</summary>
|
||||
private bool _diffPending;
|
||||
|
||||
/// <summary>이 탭이 다시 보일 때 부른다. 미뤄 둔 커밋 내용을 게이트가 빈 뒤에 그린다.</summary>
|
||||
public void ShowPendingDiff()
|
||||
{
|
||||
if (!_diffPending) return;
|
||||
_diffPending = false;
|
||||
_ = ShowDiffWhenIdleAsync();
|
||||
}
|
||||
|
||||
private async Task ShowDiffWhenIdleAsync()
|
||||
{
|
||||
await _workspace.WhenIdleAsync();
|
||||
await ShowDiffAsync(SelectedCommit);
|
||||
}
|
||||
|
||||
public CommitInfo? SelectedCommit
|
||||
{
|
||||
get => _workspace.SelectedCommit;
|
||||
set
|
||||
{
|
||||
if (ReferenceEquals(_workspace.SelectedCommit, value)) return;
|
||||
|
||||
// 사람이 다른 커밋을 고른 것이면 파일 비교 탭도 따라간다(10차 B-1, 사용자 결정).
|
||||
// 저장 안 한 편집은 목록이 선택을 바꾸기 <b>전에</b> 화면이 물었다(ConfirmChooseCommit). 목록이 비워지며 들어온 null 은 고른 것이 아니다.
|
||||
var chosen = CommitSelection.IsOtherCommit(_workspace.SelectedCommit?.Sha, value?.Sha);
|
||||
_workspace.SelectedCommit = value;
|
||||
OnPropertyChanged();
|
||||
_ = ShowDiffAsync(value);
|
||||
RaiseCanExecuteChanged();
|
||||
if (chosen) _workspace.NotifyCommitChosen(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이력 목록이 선택을 바꾸기 <b>전에</b> 화면이 부른다(마우스 누름 · 방향키). 파일 비교 탭에 저장 안 한 편집이 있으면
|
||||
/// 파일 비교 탭 이력에서 고를 때와 같은 창으로 묻고, [취소] 면 false - 화면이 그 누름을 막는다(10차 B-1).
|
||||
///
|
||||
/// 선택이 바뀐 <b>뒤에</b> 묻고 되돌리면, 창이 닫힌 뒤 목록이 누름 처리를 이어 가 [취소] 해도 다른 커밋이 선택된 채로 남았다.
|
||||
/// </summary>
|
||||
/// <param name="target">옮겨 갈 항목.</param>
|
||||
/// <returns>null = 창 없이 계속(목록이 알아서 고른다) · true = 물었고 계속(누름 도중에 창이 떠서 목록이 못 고르니 화면이 고른다) · false = [취소].</returns>
|
||||
public bool? ConfirmChooseCommit(CommitInfo? target)
|
||||
{
|
||||
if (target is null || !CommitSelection.IsOtherCommit(SelectedCommit?.Sha, target.Sha)) return null;
|
||||
return _workspace.ConfirmLeaveCommit?.Invoke();
|
||||
}
|
||||
// ================= 저장소 =================
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@ -43,6 +43,10 @@ namespace MergeHub.ViewModels
|
||||
|
||||
// Git 작업이 시작되기 전에 우리에게 물어보게 한다(5차 A-2).
|
||||
_workspace.ConfirmDiscardEdits = op => ConfirmDiscard($"Git 작업을 합니다: {op}");
|
||||
|
||||
// Git 탭에서 고른 커밋을 따라간다. 고르기 전에 저장 안 한 편집을 묻는 것도 이 화면이 맡는다(10차 B-1).
|
||||
_workspace.ConfirmLeaveCommit = () => WillAskBeforeDiscard ? ConfirmDiscard("다른 커밋을 봅니다.") : null;
|
||||
_workspace.CommitChosen += OnCommitChosenElsewhere;
|
||||
_isRulesOpen = _workspace.Settings.ActionsRulesExpanded;
|
||||
_reflowTimer.Tick += (_, _) => Reflow();
|
||||
|
||||
@ -669,13 +673,40 @@ namespace MergeHub.ViewModels
|
||||
set
|
||||
{
|
||||
if (ReferenceEquals(_workspace.SelectedCommit, value)) return;
|
||||
var chosen = CommitSelection.IsOtherCommit(_workspace.SelectedCommit?.Sha, value?.Sha);
|
||||
_workspace.SelectedCommit = value;
|
||||
OnPropertyChanged();
|
||||
RaiseCommitDetail();
|
||||
_ = LoadCommitAsync();
|
||||
|
||||
// Git 탭의 이력 선택 표시와 단추가 따라오게 알린다(10차 B-1).
|
||||
if (chosen) _workspace.NotifyCommitChosen(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Git 탭에서 다른 커밋을 골랐다. 위 줄 Selected Commit · 왼쪽 이력 선택 · 두 칸 기준이 따라간다(10차 B-1).
|
||||
/// 저장 안 한 편집은 Git 탭이 고르기 전에 <see cref="GitWorkspace.ConfirmLeaveCommit"/> 로 이미 물었다 - 여기서 또 묻지 않는다.
|
||||
/// </summary>
|
||||
private void OnCommitChosenElsewhere(object chooser)
|
||||
{
|
||||
if (ReferenceEquals(chooser, this)) return;
|
||||
|
||||
var sha = _workspace.SelectedCommit?.Sha;
|
||||
var node = _workspace.CommitNodes.FirstOrDefault(n => n.Commit.Sha == sha);
|
||||
|
||||
_syncingSelection = true;
|
||||
try { SelectedNode = node; }
|
||||
finally { _syncingSelection = false; }
|
||||
|
||||
OnPropertyChanged(nameof(SelectedCommit));
|
||||
RaiseCommitDetail();
|
||||
|
||||
// Git 탭이 방금 그 커밋의 내용(diff)을 그리느라 작업 게이트를 쥐고 있다. 바로 읽으면 건너뛰어져
|
||||
// Selected Commit 만 바뀌고 BASE 칸은 옛 커밋으로 남았다 - 게이트가 빈 뒤에 세운다(새로고침 뒤와 같은 길).
|
||||
_ = RebuildListAfterRefreshAsync();
|
||||
}
|
||||
|
||||
public string CommitHash => SelectedCommit?.ShortSha ?? "-";
|
||||
public string CommitDate => SelectedCommit is null ? "-" : SelectedCommit.When.ToString("yyyy-MM-dd");
|
||||
public string CommitAuthor => SelectedCommit?.AuthorName ?? "-";
|
||||
@ -2709,6 +2740,13 @@ namespace MergeHub.ViewModels
|
||||
/// </summary>
|
||||
private bool _suspendGuard;
|
||||
|
||||
/// <summary>
|
||||
/// 지금 <see cref="ConfirmDiscard"/> 를 부르면 창이 뜨는지. 저장 안 한 편집이 있을 때만 묻는다.
|
||||
/// 스타일 맞춤으로만 바뀐 글은 다시 열면 똑같이 만들어진다 - 묻지 않는다.
|
||||
/// 묻게 두면 스타일이 다른 파일을 훑을 때마다 창이 떠서 쓸 수가 없다.
|
||||
/// </summary>
|
||||
private bool WillAskBeforeDiscard => !_suspendGuard && HasChanges && !OnlyStyleChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 고치던 것이 있으면 물어보고, 계속해도 되면 true 를 준다.
|
||||
///
|
||||
@ -2722,12 +2760,7 @@ namespace MergeHub.ViewModels
|
||||
/// <param name="what">이제 무엇을 하려는지. 창에 그대로 적힌다.</param>
|
||||
private bool ConfirmDiscard(string what)
|
||||
{
|
||||
if (_suspendGuard) return true;
|
||||
if (!HasChanges) return true;
|
||||
|
||||
// 스타일 맞춤으로만 바뀐 글은 다시 열면 똑같이 만들어진다 - 묻지 않는다.
|
||||
// 묻게 두면 스타일이 다른 파일을 훑을 때마다 창이 떠서 쓸 수가 없다.
|
||||
if (OnlyStyleChanged) return true;
|
||||
if (!WillAskBeforeDiscard) return true;
|
||||
|
||||
// <b>고친 파일</b>의 이름을 댄다(6차 B-2). 파일을 바꿀 때는 이 창이 뜨는 순간 SelectedFile 이 이미 새 파일이라,
|
||||
// 예전에는 그 새 파일 이름을 댔다 - Motion/Unit0.cs 를 고쳤는데 "ToBeDeleted.cs 에 저장하지 않은 편집" 이라고 했다.
|
||||
|
||||
@ -411,7 +411,7 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ListBox Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Workspace.Commits}"
|
||||
<ListBox x:Name="HistoryList" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Workspace.Commits}"
|
||||
SelectedItem="{Binding SelectedCommit}" HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox.ItemTemplate>
|
||||
|
||||
@ -13,6 +13,54 @@ namespace MergeHub.Views
|
||||
public GitView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// 다른 탭에 있는 동안 파일 비교 탭에서 고른 커밋의 내용을, 이 탭이 다시 보일 때 그린다(10차 B-1).
|
||||
IsVisibleChanged += (_, e) => { if (e.NewValue is true) ViewModel?.ShowPendingDiff(); };
|
||||
|
||||
// 이력에서 다른 커밋을 누르면 파일 비교 탭도 따라간다. 거기 저장 안 한 편집이 있으면 선택이 바뀌기 전에 묻고,
|
||||
// [취소] 면 누름을 막아 선택이 그대로다(10차 B-1).
|
||||
HistoryList.PreviewMouseLeftButtonDown += (_, e) =>
|
||||
{
|
||||
if (ViewModel is not { } vm) return;
|
||||
if (ItemsControl.ContainerFromElement(HistoryList, e.OriginalSource as DependencyObject) is not ListBoxItem item) return;
|
||||
if (item.DataContext is not MergeHub.Models.CommitInfo target) return;
|
||||
|
||||
var answer = vm.ConfirmChooseCommit(target);
|
||||
if (answer is null) return; // 물을 것 없음 - 목록이 여느 때처럼 고른다
|
||||
e.Handled = true; // [취소] 거나, 창이 누름을 끊어 목록이 스스로 못 고른다
|
||||
if (answer == true) ChooseHistoryRow(vm, HistoryList.Items.IndexOf(target));
|
||||
};
|
||||
HistoryList.PreviewKeyDown += (_, e) =>
|
||||
{
|
||||
if (ViewModel is not { } vm) return;
|
||||
var at = HistoryList.SelectedIndex;
|
||||
var to = e.Key switch
|
||||
{
|
||||
System.Windows.Input.Key.Up => at - 1,
|
||||
System.Windows.Input.Key.Down => at + 1,
|
||||
System.Windows.Input.Key.Home => 0,
|
||||
System.Windows.Input.Key.End => HistoryList.Items.Count - 1,
|
||||
System.Windows.Input.Key.PageUp => at - 10,
|
||||
System.Windows.Input.Key.PageDown => at + 10,
|
||||
_ => at
|
||||
};
|
||||
to = System.Math.Max(0, System.Math.Min(HistoryList.Items.Count - 1, to));
|
||||
if (to == at) return;
|
||||
|
||||
var answer = vm.ConfirmChooseCommit(HistoryList.Items[to] as MergeHub.Models.CommitInfo);
|
||||
if (answer is null) return;
|
||||
e.Handled = true;
|
||||
if (answer == true) ChooseHistoryRow(vm, to);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>물은 뒤 [계속] 이면 그 커밋을 직접 고른다. 창이 누름을 끊어 목록이 스스로 고르지 못한다(10차 B-1).</summary>
|
||||
private void ChooseHistoryRow(GitViewModel vm, int index)
|
||||
{
|
||||
if (index < 0 || index >= HistoryList.Items.Count) return;
|
||||
vm.SelectedCommit = HistoryList.Items[index] as MergeHub.Models.CommitInfo;
|
||||
HistoryList.ScrollIntoView(HistoryList.Items[index]);
|
||||
(HistoryList.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem)?.Focus();
|
||||
}
|
||||
|
||||
private GitViewModel? ViewModel => DataContext as GitViewModel;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user